【问题标题】:Iterate over nested dictionary迭代嵌套字典
【发布时间】:2011-12-01 00:32:12
【问题描述】:

有没有一种简单的方法来迭代嵌套字典,它可能包含其他对象,如列表、元组,然后是字典,以便迭代覆盖这些其他对象的所有元素?

例如,如果我键入一个嵌套字典对象的键,我会将其全部列在 Python 解释器中。


[编辑]这里是字典示例:

{
'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']
                }
            },
     }
}

对不起,我读不明白,但我已尽我所能。

【问题讨论】:

  • 对于问题的第二部分,您可能需要a pretty printer
  • 为什么不提供理由就拒绝投票?问题问得不好?字典对象示例不好吗?它只是更大字典的一部分,如果可能的话,我想以自动化方式使用 graphviz 而无需手动爬行
  • 好吧,有些人看到其他人试图遍历字典或哈希表时会很高兴
  • 为什么没有公认的答案? Graddy 和 @NeilenMarais 的解决方案效果很好。

标签: python


【解决方案1】:

上面 Graddy 的 recurse() 答案的生成器版本不应在字符串上爆炸,并且还为您提供复合键(cookie crumb trail?)显示您如何达到某个值:

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 循环应该可以替换为 yield from。通过使用集合模块中的 Mapping ABC 将 type(d) == dict 测试替换为 isinstance(d, collections.Mapping),可以使这个生成器更加通用。

【讨论】:

    【解决方案2】:
    def recurse(d):
      if type(d)==type({}):
        for k in d:
          recurse(d[k])
      else:
        print d
    

    【讨论】:

    • @theta: 工作正常,对于您的问题的一种解释。如果您还希望它循环遍历列表,请添加elif isinstance([], (list, tuple)):,然后添加for v in d: recurse(v)
    • 注意:递归方法在大型嵌套字典的情况下失败...给出错误:超出最大递归深度。所以这取决于你的要求。如果出现大型嵌套字典问题,请使用迭代。
    【解决方案3】:

    这是另一种解决方案,

    #!/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
    

    【讨论】:

      【解决方案4】:

      遍历包含意外嵌套元素的嵌套字典。

      这是我的解决方案:

      # 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
      

      我认为上面的例子很笼统,你可以根据你的用例来塑造它。

      【讨论】:

        【解决方案5】:

        使用通用包装器生成器怎么样,如下所示:

        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
        

        【讨论】:

        • 我得到:RuntimeError: maximum recursion depth exceeded
        • 字符串是可迭代的,所以如果您在列表/字典中有任何字符串,这将会爆炸
        【解决方案6】:

        我拿了你字典的一小部分

        d = {
            'key_1': 'value_1',
            'key_2': {'key_21': [(2100, 2101), (2110, 2111)]},
            'key_22': ['l1', 'l2'],
            'key_23': {'key_231': 'v'}
        }
        

        使用NestedDict 可以直接访问所有值。

        >>> from ndicts.ndicts import NestedDict
        >>> nd = NestedDict(d)
        >>> list(nd.values())
        ['value_1', [(2100, 2101), (2110, 2111)], ['l1', 'l2'], 'v']
        

        如果你想展平这个列表,你可以使用这个递归函数

        from typing import Iterable
        
        def flatten(li):
            def wrap(x, result):
                if isinstance(x, Iterable) and type(x) is not str:
                    for i in x:
                        wrap(i, result)
                else:
                    result.append(x)
            result = []
            wrap(li, result)
            return result
        
        >>> flatten(list(nd.values()))
        ['value_1', 2100, 2101, 2110, 2111, 'l1', 'l2', 'v']
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-01-21
          • 2019-10-17
          • 2021-01-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-05
          相关资源
          最近更新 更多