2015-02-25 6 views
0

Я повторяю сложный объект json, загружаемый как словарь в python. Ниже приведен пример json-файла. Прокомментированные данные.Простой способ перебросить сложный словарь в python?

{ 
    "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-файл, который не меняет структуру в течение нескольких месяцев - возможно, лет - и поэтому я считаю, что мое первоначальное использование для ключа в результате ["value"] ["timeSeries"]: - это хорошо, но Я не уверен, что многие, многие из циклов не нужны или неэффективны. Есть ли простой способ поиска и возврата пар ключ: значение из такого иерархического словаря со списками словарей внутри списков словарей?

EDIT:

На основе решения представленного @Alex Мартелла, здесь новая, более эффективная, отделанную версию коды:

# 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 строку код. Более быстрое время работы. Ницца.

EDIT:

На основе решения, предложенного @ двухбитовая 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, проверки, которые должны гарантировать, что ошибки не будут введены, если значения возвращаются из ошибочных запросов.

EDIT:

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 
+0

Думаю, вам просто нужно получить к нему доступ, не так ли? Что-то вроде 'dct ['value'] ['timeSeries'] [0] ['values'] [0] ['value'] [0] ['qualifiers']' if 'dct' - ваша структура json. Это может быть не совсем правильно, потому что, да, эта вещь чрезвычайно сложна! –

+0

Итак, это сработает, если я знаю, сколько ответов на мой запрос может быть. Но в любой момент времени может быть от одного до десятка ответов, и я точно не знаю, сколько ответов, и поэтому я не знаю, сколько я должен разместить (или перебрать) в вашем решении. Если бы я всегда знал общее количество ответов, ваше предложение будет работать. Но я не уверен, может ли это иначе. – traggatmot

+0

Какую часть этой структуры вы называете «ответом», что существует переменное число? –

ответ

5

Вы спрашиваете «какую-либо очевидную неэффективность в моем коде» - ответ да, то где конкретно вы цикл над словарями (таким образом, получая все свои ключи последовательно, что O(N), т. Е. Занимает время, пропорциональное количеству ключей в словаре), а не просто использовать их в качестве словарей (что занимает время O(1), то есть постоянное время - быстрая тоже).

Так, например, когда у вас есть

for key2 in key: 
    if key2 == "values": 
     ...use key.get(key2)... 
    if key2 == "name": 
     ...use key.get(key2)... 

вместо него вы должны иметь:

if 'values' in key: 
    ...use key['values']... 
if 'name' in key: 
    ...use key['name']... 

и подобные конструкции глубже в вещи могут быть оптимизированы далее, например, с:.

values = key.get('values') 
if values is not None: 
    ...use values... 
name = key.get('name') 
if name is not None: 
    ...use name... 

, чтобы избежать повторения индексации (опять же, глубже).

+0

Спасибо! Я пока не совсем понимаю, но я буду работать над этим! – traggatmot

+0

Оператор 'in', когда RHS является словарем, возвращает true, если LHS является ключом в этом словаре. Метод 'get' словаря возвращает' None' при вызове с аргументом, который ** не ** является ключом в этом словаре. Вот и все! Кстати, не забудьте в конце концов ** принять ** ответ, т. Е. Щелкнуть по схеме галочки слева от него ... если вы не получите лучшего, который кажется маловероятным к настоящему времени :-) –

+0

О публикации моей реализации - посмотрите если я пропустил какой-либо выигрыш в эффективности. Спасибо! – traggatmot

0

Как я понимаю этот вопрос, я считаю, что ваш первоначальный озадачивающий подход к проблеме, который является массово излишним, омрачил очень простое решение. Пожалуйста, поправьте меня, если я все еще недопонимаю это и упрощаю. Несмотря на то, что эта структура очень сложна, если ее переменная часть - это длина списка в timeSeries, вы можете просто получить доступ к этому списку и перебрать его, не раз хватая ваши «данные, представляющие интерес». Я не знаю, что это данные, чтобы дать вам хорошую структуру данных примера или даже достойные имена переменных для того, как они должны быть сохранены для использования позже в вашей программе, поэтому я просто собираюсь хранить ее в большом списке списки, чтобы показать вам, как я имею в виду:

data_of_interest = [] 
for data in json_structure['value']['timeSeries']: 
    value_list = data['values'][0]['value'] 
    # qualifiers is a list containing ["P", "Ice"] 
    qualifiers = value_list[0]['qualifiers'] 
    value = value_list[1]['value'] 
    dateTime = value_list[1]['dateTime'] 
    data_of_interest.append([qualifiers, value, dateTime]) 

Если есть повторы в других местах, где я жестко закодированные индекс 0, просто ввести для петель там, например,

for data in json_structure['value']['timeSeries']: 
    for value_set in data['values']: 
     for value_list in value_set['value']: 
      # etc 

Если вы обеспокоены некоторые значения не там, просто будьте готовы поймать KeyError от Словаря или эквивалента.

Например, когда я пишу:

value = value_list[1]['value'] 

Это может поднять IndexError если value_list не имеет> = 2 значения, или KeyError, если его второй элемент не ДИКТ отображение «значение» к чему-то , Вы можете поймать один или оба из них и обрабатывать их вместе или по отдельности или просто игнорировать их и продолжать.

try: 
    value = value_list[1]['value'] 
except KeyError: # catch only one 
    # do something 

или

try: 
    value = value_list[1]['value'] 
except (IndexError, KeyError): # catch both 
    # handle together 

или

try: 
    value = value_list[1]['value'] 
except IndexError: 
    # handle IndexError 
except KeyError: 
    # handle KeyError 

и ваш # handle whatever код также может быть pass - который просто означает, что «я знаю, что это может произойти, но не урод. Просто продолжай читать. Если вы не поймать их, исключения будут «пузыряться» до вершины контекста выполнения и сбой вашей программы.

+0

Я проверю это. – traggatmot

+0

Обновлен вопрос, чтобы показать реализацию вашего решения. Я все еще беспокоюсь об этом, так как он теряет проверки, предоставляемые if-утверждениями. Я считаю, хотя я не совсем уверен, что эти if-утверждения должны предотвращать сбой кода, когда результат запроса не содержит ожидаемых значений. – traggatmot

+0

Великая вещь о словарях заключается в том, что они поднимут «KeyError», если эти значения отсутствуют. Так что просто объедините свои обращения с помощью try/except и поймите это. Я уточню свой ответ. –

Смежные вопросы