Перебирать вложенный словарь - PullRequest
19 голосов
/ 01 декабря 2011

Существует ли простой способ перебора вложенного словаря, который может состоять из других объектов, таких как списки, кортежи, а затем словари, чтобы итерация охватывала все элементы этих других объектов?

Например, еслиЯ набираю ключ вложенного словарного объекта, я хотел бы получить его все перечисленные в интерпретаторе Python.


[edit] вот пример словаря:

{
'key_1': 'value_1',
'key_2': {'key_21': [(2100, 2101), (2110, 2111)],
      'key_22': ['l1', 'l2'],
      'key_23': {'key_231': 'v'},
      'key_24': {'key_241': 502,
             'key_242': [(5, 0), (7, 0)],
             'key_243': {'key_2431': [0, 0],
                 'key_2432': 504,
                 'key_2433': [(11451, 0), (11452, 0)]
                },
             'key_244': {'key_2441': {'key_24411': {'key_244111': 'v_24411',
                                'key_244112': [(5549, 0)]
                               },
                          'key_24412':'v_24412'
                         },
                 'key_2441': ['ll1', 'll2']
                }
            },
     }
}

извините за то, что я не читал, но я сделал все, что мог.

Ответы [ 5 ]

18 голосов
/ 01 декабря 2011
def recurse(d):
  if type(d)==type({}):
    for k in d:
      recurse(d[k])
  else:
    print d
4 голосов
/ 15 июля 2015

Генераторная версия ответа Грэдди recurse() выше, который не должен взрываться на строках, а также дает вам составной ключ (след крошки печенья?), Показывающий, как вы достигли определенного значения:

def recurse(d, keys=()):
    if type(d) == dict:
         for k in d:
            for rv in recurse(d[k], keys + (k, )):
                yield rv
    else:
        yield (keys, d)

for compound_key, val in recurse(eg_dict):
    print '{}: {}'.format(compound_key, val)

производит вывод (используя пример словаря, приведенный в вопросе):

('key_1',): value_1
('key_2', 'key_21'): [(2100, 2101), (2110, 2111)]
('key_2', 'key_22'): ['l1', 'l2']
('key_2', 'key_23', 'key_231'): v
('key_2', 'key_24', 'key_241'): 502
('key_2', 'key_24', 'key_243', 'key_2433'): [(11451, 0), (11452, 0)]
('key_2', 'key_24', 'key_243', 'key_2432'): 504
('key_2', 'key_24', 'key_243', 'key_2431'): [0, 0]
('key_2', 'key_24', 'key_242'): [(5, 0), (7, 0)]
('key_2', 'key_24', 'key_244', 'key_2441'): ['ll1', 'll2']

В Python 3 второй цикл выхода должен быть заменен на yield from. Этот генератор можно сделать более общим, заменив тест type(d) == dict на isinstance(d, collections.Mapping), используя Азбуку сопоставления из модуля коллекций.

2 голосов
/ 03 февраля 2014

Вот еще одно решение,

#!/usr/bin/python

d = {'key_1': 'value_1',
     'key_2': {'key_21': [(2100, 2101), (2110, 2111)],
           'key_22': ['l1', 'l2'],
           'key_23': {'key_231': 'v'},
           'key_24': {'key_241': 502,
                      'key_242': [(5, 0), (7, 0)],
                      'key_243': {'key_2431': [0, 0],
                                  'key_2432': 504,
                                  'key_2433': [(11451, 0), (11452, 0)]},
                      'key_244': {'key_2441': ['ll1', 'll2']}}}}

def search_it(nested, target):
    found = []
    for key, value in nested.iteritems():
        if key == target:
            found.append(value)
        elif isinstance(value, dict):
            found.extend(search_it(value, target))
        elif isinstance(value, list):
            for item in value:
                if isinstance(item, dict):
                    found.extend(search_it(item, target))
        else:
            if key == target:
                found.append(value)
    return found

keys = [ 'key_242', 'key_243', 'key_242', 'key_244', 'key_1' ]

for key in keys:
    f = search_it(d, key)
    print 'Key: %s, value: %s' % (key, f[0])

Выход:

Key: key_242, value: [(5, 0), (7, 0)]
Key: key_243, value: {'key_2433': [(11451, 0), (11452, 0)], 'key_2432': 504, 'key_2431': 
 [0, 0]}
Key: key_242, value: [(5, 0), (7, 0)]
Key: key_244, value: {'key_2441': ['ll1', 'll2']}
Key: key_1, value: value_1
2 голосов
/ 01 декабря 2011

Перебор вложенного словаря, содержащего неожиданные вложенные элементы.

Вот мое решение:

# d is the nested dictionary

for item in d:
    if type(item) == list:
        print "Item is a list"
        for i in item: print i
    elif type(item) == dict:
        print "Item is a dict"
        for i in item: print i
    elif type(item) == tuple:
        print "Item is a tuple"
        for i in item: print i
    else:
        print "Item is not a list, neither a dict and not even a tuple"
        print item

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

0 голосов
/ 01 декабря 2011

Как насчет использования генератора обертки общего назначения, например:

def recursive(coll):
    """Return a generator for all atomic values in coll and its subcollections.
    An atomic value is one that's not iterable as determined by iter."""
    try:
        k = iter(coll)
        for x in k:
            for y in recursive(x):
                yield y
    except TypeError:
        yield coll


def test():
    t = [[1,2,3], 4, 5, [6, [7, 8], 9]]
    for x in recursive(t):
        print x
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...