Как перебирать вложенный словарь python со структурой ниже?

#python-3.x #collections

#python-3.x #Коллекции

Вопрос:

У меня есть вложенный словарь со структурой ниже. Как и ключ values , может быть несколько ключей, например values1 , values2 . Я ищу random1 и random2 строки. Если существует, то нужно проверить val , существует или нет.

 d = {"values": [
        {
          "name": "A1234",
          "description": "A1234-Description ",
          "random1": {
            "abcd": {
              "val": 1
            }
          },
          "random2": {
            "abcd": {
              "val": -1
            }
          }
        },
        {
        "name": "A4567",
          "description": "A4567-Description ",
          "random1": {
            "abcd": {
              "val": 1
            }
          },
          "random2": {
            "abcd": {
              "val": -1
            }
          }
        },
        {
          "name": "B1234",
          "description": "B1234-Description ",
        }
    ]}
  

Код:

 for i in d["values"]:
    for k, v in i.items():
        if k in ("random1", "random2") and "abcd" in v1:
           if len(v1["abcd"]) != 0:
              if "val" in v1["abcd"]:
                  print("Found")
              else:
                  print("Not found")
           else:
               print("empty")
  

Я считаю, что нет ярлыка для перехода к словарю. Но, безусловно, для этого должны быть некоторые методы / оптимизация (сокращение количества циклов for / if)

Может кто-нибудь, пожалуйста, подсказать мне, можно ли это сделать с помощью коллекций и т. Д

Комментарии:

1. Каков ваш желаемый результат? A Found, Not Found, empty для каждого randonm[12] -> abcd ?

2. @schwobaseggl: для каждого random1 или random2 ‘val’ найден или не найден.

Ответ №1:

Вам нужен рекурсивный алгоритм, чтобы пройти через древовидность словаря

 def recursive_iter(obj, keys=()):
    if isinstance(obj, dict):
        for k, v in obj.items():
            yield from recursive_iter(v, keys   (k,))
    elif any(isinstance(obj, t) for t in (list, tuple)):
        for idx, item in enumerate(obj):
            yield from recursive_iter(item, keys   (idx,))
    else:
        yield keys, obj
  

Здесь вы можете распечатать результат

 for keys, item in recursive_iter(d):
    print(keys, ' -> ', item)
  

Который отображает :

 ('values', 0, 'name')  ->  A1234
('values', 0, 'description')  ->  A1234-Description 
('values', 0, 'random1', 'abcd', 'val')  ->  1
('values', 0, 'random2', 'abcd', 'val')  ->  -1
('values', 1, 'name')  ->  A4567
('values', 1, 'description')  ->  A4567-Description 
('values', 1, 'random1', 'abcd', 'val')  ->  1
('values', 1, 'random2', 'abcd', 'val')  ->  -1
('values', 2, 'name')  ->  B1234
('values', 2, 'description')  ->  B1234-Description
  

Редактировать:

 for keys, item in recursive_iter(d):
    if "val" in keys and "abcd" in keys:
        print("FOUNDn", keys, ' -> ', item)
    elif "val" not in keys and "abcd" in keys:
        print("NOT FOUNDn", keys, ' -> ', item)
  

Комментарии:

1. мы должны убедиться, что «val» означает «abcd» для ‘random1’ или ‘random2’ или обоих.

2. почему эта проверка item == 1 и item == -1 ?

3. независимо от того, val = 1 или -1, просто чтобы проверить, существует ли «val» для «abcd» ‘random1’ или ‘random2’ или обоих

4. Если в порядке словаря, если что-либо, кроме ‘random1’ и ‘random2’ в d [«values»] [index].keys(), не должно беспокоить. Следует учитывать, если это только ‘random1’ ‘random2’

5.Я отредактировал. На самом деле, поскольку ваш запрос не касается рекурсивного исследования, и если ваш словарь всегда в этом формате, ваш скрипт уже хорош. Вы можете пропустить второй for цикл и включить в свой if оператор : if 'random1' in i and 'abcd' in i['random1']: if 'random2' in i and 'abcd' in i['random2']: if 'random1' not in i and 'random2' not in i: