【发布时间】:2015-02-25 02:24:24
【问题描述】:
我正在迭代作为字典加载到 python 中的复杂 json 对象。以下是 json 文件的示例。对感兴趣的数据进行了注释。
{
"name":"ns1:timeSeriesResponseType",
"nil":false,
"value":{
"queryInfo":{ },
"timeSeries":[
{
"variable":{ },
"values":[
{
"qualifier":[ ],
"censorCode":[ ],
"value":[
{
"codedVocabularyTerm":null,
"censorCode":null,
"offsetTypeID":null,
"accuracyStdDev":null,
"timeOffset":null,
"qualifiers":[
"P", # data of interest
"Ice" # data of interest
],
"qualityControlLevelCode":null,
"sampleID":null,
"dateTimeAccuracyCd":null,
"methodCode":null,
"codedVocabulary":null,
"sourceID":null,
"oid":null,
"dateTimeUTC":null,
"offsetValue":null,
"metadataTime":null,
"labSampleCode":null,
"methodID":null,
"value":"-999999",
"dateTime":"2015-02-24T03:30:00.000-05:00",
"offsetTypeCode":null,
"sourceCode":null
},
{
"codedVocabularyTerm":null,
"censorCode":null,
"offsetTypeID":null,
"accuracyStdDev":null,
"timeOffset":null,
"qualifiers":[ ],
"qualityControlLevelCode":null,
"sampleID":null,
"dateTimeAccuracyCd":null,
"methodCode":null,
"codedVocabulary":null,
"sourceID":null,
"oid":null,
"dateTimeUTC":null,
"offsetValue":null,
"metadataTime":null,
"labSampleCode":null,
"methodID":null,
"value":"-999999", # data of interest
"dateTime":"2015-02-24T04:00:00.000-05:00", # data of interest
"offsetTypeCode":null,
"sourceCode":null
}
],
"sample":[ ],
"source":[ ],
"offset":[ ],
"units":null,
"qualityControlLevel":[ ],
"method":[ ]
}
],
"sourceInfo":{ },
"name":"USGS:03193000:00060:00011"
},
{ }, # more data need is stored in here
{ }, # more data need is stored in here
{ } # more data need is stored in here
]
},
"declaredType":"org.cuahsi.waterml.TimeSeriesResponseType",
"scope":"javax.xml.bind.JAXBElement$GlobalScope",
"globalScope":true,
"typeSubstituted":false
}
这是我的代码,用于单步执行/迭代字典以获取我想要的数据并将其存储在格式更简单的字典中:
# Setting up blank variables to store results
outputDict = {}
outputList = []
dateTimeList = []
valueList = []
qualifiersList = [[]]
for key in result["value"]["timeSeries"]:
for key2 in key:
if key2 == "values":
for key3 in key.get(key2):
for key4 in key3:
if key4 == "value":
for key5 in key3.get(key4):
for key6 in key5:
if key6 == "value":
valueList.append(key5.get(key6))
if key6 == "dateTime":
dateTimeList.append(key5.get(key6))
#print key.get("name")
#outputDict[key.get("name")]["dateTime"] = dateTimeList
#outputDict[key.get("name")]["values"] = valueList
if key2 == "name":
outputList.append(key.get(key2))
outputDict[key.get(key2)]={"dateTime":None, "values":None, "qualifiers":None}
outputDict[key.get("name")]["dateTime"] = dateTimeList
outputDict[key.get("name")]["values"] = valueList
del dateTimeList[:]
del valueList[:]
我的问题是——对 python 有点陌生,谁能指出我的代码中任何明显的低效率?我可以指望 json 文件在几个月(可能是几年)内不会改变结构,所以我相信我最初使用 for 键在 result["value"]["timeSeries"]: 很好,但我不确定很多很多 for 循环是否不必要或效率低下。有没有一种简单的方法可以从这样的分层字典中搜索并返回键:值对,字典列表位于字典列表中?
编辑:
基于@Alex Martelli 提供的解决方案,这里是新的、更高效、精简的代码版本:
# Building the output dictionary
for key in result["value"]["timeSeries"]:
if "values" in key:
for key2 in key.get("values"):
if "value" in key2:
for key3 in key2.get("value"):
if "value" in key3:
valueList.append(key3.get("value"))
if "dateTime" in key3:
dateTimeList.append(key3.get("dateTime"))
if "qualifiers" in key3:
qualifiersList.append(key3.get("qualifiers"))
if "name" in key:
outputList.append(key.get("name"))
outputDict[key.get("name")]={"dateTime":None, "values":None, "qualifiers":None}
outputDict[key.get("name")]["dateTime"] = dateTimeList[:] # passing the items in the list rather
outputDict[key.get("name")]["values"] = valueList[:] # than a reference to the list so the delete works
outputDict[key.get("name")]["qualifiers"] = qualifiersList[:] # than a reference to the list so the delete works
del dateTimeList[:]
del valueList[:]
del qualifiersList[:]
工作原理相同,删除了 4 行代码。运行时间更快。不错。
编辑:
基于@Two-Bit Alchemist 提出的解决方案,这同样有效:
# Building the output dictionary
for key in result["value"]["timeSeries"]:
print key
for value in key["values"][0]["value"]:
# qualifiers is a list containing ["P", "Ice"]
qualifiersList.append(value['qualifiers'])
valueList.append(value['value'])
dateTimeList.append(value['dateTime'])
if "name" in key:
outputList.append(key.get("name"))
outputDict[key.get("name")]={"dateTime":None, "values":None, "qualifiers":None}
outputDict[key.get("name")]["dateTime"] = dateTimeList[:] # passing the items in the list rather
outputDict[key.get("name")]["values"] = valueList[:] # than a reference to the list so the delete works
outputDict[key.get("name")]["qualifiers"] = qualifiersList[:] # than a reference to the list so the delete works
del dateTimeList[:]
del valueList[:]
del qualifiersList[:]
我看到的唯一问题是我无法完全确定 ["values"] 列表中的第一个位置是我想要的。而且我丢失了“if”语句提供的检查,这些检查应该确保在错误的查询语句返回值时不会引入错误。
编辑:
try:
# requests.get returns a "file-like" object
# in this case it is a JSON object because of the settings in the query
response = requests.get(url=query)
# if-else ladder that only performs the parsing of the returned JSON object
# when the HTTP status code indicates a successful query execution
if(response.status_code == 200):
# parsing the
result = response.json()
# Setting up blank variables to store results
outputDict = {}
outputList = []
dateTimeList = []
valueList = []
qualifiersList = []
# Building the output dictionary
for key in result["value"]["timeSeries"]:
print key
for value in key["values"][0]["value"]:
# qualifiers is a list containing ["P", "Ice"]
qualifiersList.append(value['qualifiers'])
valueList.append(value['value'])
dateTimeList.append(value['dateTime'])
# OLD CODE
# if "values" in key:
# for key2 in key.get("values"):
# if "value" in key2:
# for key3 in key2.get("value"):
# if "value" in key3:
# valueList.append(key3.get("value"))
# if "dateTime" in key3:
# dateTimeList.append(key3.get("dateTime"))
# if "qualifiers" in key3:
# qualifiersList.append(key3.get("qualifiers"))
if "name" in key:
outputList.append(key.get("name"))
outputDict[key.get("name")]={"dateTime":None, "values":None, "qualifiers":None}
outputDict[key.get("name")]["dateTime"] = dateTimeList[:] # passing the items in the list rather
outputDict[key.get("name")]["values"] = valueList[:] # than a reference to the list so the delete works
outputDict[key.get("name")]["qualifiers"] = qualifiersList[:] # than a reference to the list so the delete works
del dateTimeList[:]
del valueList[:]
del qualifiersList[:]
# Tracking how long it took to process the data
elapsed = time.time() - now
print "Runtime: " + str(elapsed)
out = {"Status": 'ok', "Results": [[{"myResult": outputDict}]]}
elif(response.status_code == 400):
raise Exception("Bad Request, "+ datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
elif(response.status_code== 403):
raise Exception("Access Forbidden, "+ datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
elif(response.status_code == 404):
raise Exception("Gage location(s) not Found, "+ datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
elif(response.status_code == 500):
raise Exception("Internal Server Error, "+ datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
elif(response.status_code == 503):
raise Exception("Service Unavailable, "+ datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
else:
raise Exception("Unknown Response, "+ datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
except:
out = {"Status": 'Error', "Message": str(sys.exc_info()[1])}
print out
【问题讨论】:
-
我想你只需要访问它,对吧?如果
dct是您的json 结构,则类似于dct['value']['timeSeries'][0]['values'][0]['value'][0]['qualifiers']。这可能并不完全正确,因为,是的,这件事非常复杂! -
所以,如果我知道对我的查询可能有多少响应,这将起作用。但是,任何时候都可能有 1 到几十个响应,我不知道有多少响应,所以我不知道在您的解决方案中放置(或循环)多少 i。如果我总是知道回复的总数,你的建议会奏效。但我不确定它是否可以。
-
你将这个结构的哪一部分称为“响应”,其中有可变数量?
-
啊,是的 - 我不够清楚。整个结构 - 加载到 python 字典中的 json 对象 - 是对 Web 服务查询的响应。内部两个主要部分“timeSeries”(包含我感兴趣的所有数据)和“queryInfo”(我不感兴趣)将根据我针对 Web 服务执行的查询的特定属性而增长.我需要编写此代码来处理可能返回“timeSeries”下的字典列表中包含 1 到几十个成员的列表的查询。
-
我仍然很困惑为什么这个问题不能用 one for loop 解决——我坦率地承认我可能仍然误解了这个问题。类似
for data in json_structure['value']['timeSeries']: data['values'][0]['value'][0]['qualifiers'] # etc的东西——如果存储在timeSeries的列表长度未知,只需遍历它并重复该过程。
标签: python dictionary iteration