Loop through all nested dictionary values?

前端 未结 12 1242
温柔的废话
温柔的废话 2020-11-22 09:16
for k, v in d.iteritems():
    if type(v) is dict:
        for t, c in v.iteritems():
            print \"{0} : {1}\".format(t, c)

I\'m trying to l

相关标签:
12条回答
  • 2020-11-22 09:48

    These answers work for only 2 levels of sub-dictionaries. For more try this:

    nested_dict = {'dictA': {'key_1': 'value_1', 'key_1A': 'value_1A','key_1Asub1': {'Asub1': 'Asub1_val', 'sub_subA1': {'sub_subA1_key':'sub_subA1_val'}}},
                    'dictB': {'key_2': 'value_2'},
                    1: {'key_3': 'value_3', 'key_3A': 'value_3A'}}
    
    def print_dict(dictionary):
        dictionary_array = [dictionary]
        for sub_dictionary in dictionary_array:
            if type(sub_dictionary) is dict:
                for key, value in sub_dictionary.items():
                    print("key=", key)
                    print("value", value)
                    if type(value) is dict:
                        dictionary_array.append(value)
    
    
    
    print_dict(nested_dict)
    
    0 讨论(0)
  • 2020-11-22 09:51

    There are potential problems if you write your own recursive implementation or the iterative equivalent with stack. See this example:

        dic = {}
        dic["key1"] = {}
        dic["key1"]["key1.1"] = "value1"
        dic["key2"]  = {}
        dic["key2"]["key2.1"] = "value2"
        dic["key2"]["key2.2"] = dic["key1"]
        dic["key2"]["key2.3"] = dic
    

    In the normal sense, nested dictionary will be a n-nary tree like data structure. But the definition doesn't exclude the possibility of a cross edge or even a back edge (thus no longer a tree). For instance, here key2.2 holds to the dictionary from key1, key2.3 points to the entire dictionary(back edge/cycle). When there is a back edge(cycle), the stack/recursion will run infinitely.

                              root<-------back edge
                            /      \           |
                         _key1   __key2__      |
                        /       /   \    \     |
                   |->key1.1 key2.1 key2.2 key2.3
                   |   /       |      |
                   | value1  value2   |
                   |                  | 
                  cross edge----------|
    

    If you print this dictionary with this implementation from Scharron

        def myprint(d):
          for k, v in d.items():
            if isinstance(v, dict):
              myprint(v)
            else:
              print "{0} : {1}".format(k, v)
    

    You would see this error:

        RuntimeError: maximum recursion depth exceeded while calling a Python object
    

    The same goes with the implementation from senderle.

    Similarly, you get an infinite loop with this implementation from Fred Foo:

        def myprint(d):
            stack = list(d.items())
            while stack:
                k, v = stack.pop()
                if isinstance(v, dict):
                    stack.extend(v.items())
                else:
                    print("%s: %s" % (k, v))
    

    However, Python actually detects cycles in nested dictionary:

        print dic
        {'key2': {'key2.1': 'value2', 'key2.3': {...}, 
           'key2.2': {'key1.1': 'value1'}}, 'key1': {'key1.1': 'value1'}}
    

    "{...}" is where a cycle is detected.

    As requested by Moondra this is a way to avoid cycles (DFS):

    def myprint(d): 
      stack = list(d.items()) 
      visited = set() 
      while stack: 
        k, v = stack.pop() 
        if isinstance(v, dict): 
          if k not in visited: 
            stack.extend(v.items()) 
          else: 
            print("%s: %s" % (k, v)) 
          visited.add(k)
    
    0 讨论(0)
  • 2020-11-22 09:53

    Since a dict is iterable, you can apply the classic nested container iterable formula to this problem with only a couple of minor changes. Here's a Python 2 version (see below for 3):

    import collections
    def nested_dict_iter(nested):
        for key, value in nested.iteritems():
            if isinstance(value, collections.Mapping):
                for inner_key, inner_value in nested_dict_iter(value):
                    yield inner_key, inner_value
            else:
                yield key, value
    

    Test:

    list(nested_dict_iter({'a':{'b':{'c':1, 'd':2}, 
                                'e':{'f':3, 'g':4}}, 
                           'h':{'i':5, 'j':6}}))
    # output: [('g', 4), ('f', 3), ('c', 1), ('d', 2), ('i', 5), ('j', 6)]
    

    In Python 2, It might be possible to create a custom Mapping that qualifies as a Mapping but doesn't contain iteritems, in which case this will fail. The docs don't indicate that iteritems is required for a Mapping; on the other hand, the source gives Mapping types an iteritems method. So for custom Mappings, inherit from collections.Mapping explicitly just in case.

    In Python 3, there are a number of improvements to be made. As of Python 3.3, abstract base classes live in collections.abc. They remain in collections too for backwards compatibility, but it's nicer having our abstract base classes together in one namespace. So this imports abc from collections. Python 3.3 also adds yield from, which is designed for just these sorts of situations. This is not empty syntactic sugar; it may lead to faster code and more sensible interactions with coroutines.

    from collections import abc
    def nested_dict_iter(nested):
        for key, value in nested.items():
            if isinstance(value, abc.Mapping):
                yield from nested_dict_iter(value)
            else:
                yield key, value
    
    0 讨论(0)
  • 2020-11-22 09:57

    Slightly different version I wrote that keeps track of the keys along the way to get there

    def print_dict(v, prefix=''):
        if isinstance(v, dict):
            for k, v2 in v.items():
                p2 = "{}['{}']".format(prefix, k)
                print_dict(v2, p2)
        elif isinstance(v, list):
            for i, v2 in enumerate(v):
                p2 = "{}[{}]".format(prefix, i)
                print_dict(v2, p2)
        else:
            print('{} = {}'.format(prefix, repr(v)))
    

    On your data, it'll print

    data['xml']['config']['portstatus']['status'] = u'good'
    data['xml']['config']['target'] = u'1'
    data['xml']['port'] = u'11'
    

    It's also easy to modify it to track the prefix as a tuple of keys rather than a string if you need it that way.

    0 讨论(0)
  • 2020-11-22 10:00

    Alternative iterative solution:

    def myprint(d):
        stack = d.items()
        while stack:
            k, v = stack.pop()
            if isinstance(v, dict):
                stack.extend(v.iteritems())
            else:
                print("%s: %s" % (k, v))
    
    0 讨论(0)
  • 2020-11-22 10:02

    I am using the following code to print all the values of a nested dictionary, taking into account where the value could be a list containing dictionaries. This was useful to me when parsing a JSON file into a dictionary and needing to quickly check whether any of its values are None.

        d = {
                "user": 10,
                "time": "2017-03-15T14:02:49.301000",
                "metadata": [
                    {"foo": "bar"},
                    "some_string"
                ]
            }
    
    
        def print_nested(d):
            if isinstance(d, dict):
                for k, v in d.items():
                    print_nested(v)
            elif hasattr(d, '__iter__') and not isinstance(d, str):
                for item in d:
                    print_nested(item)
            elif isinstance(d, str):
                print(d)
    
            else:
                print(d)
    
        print_nested(d)
    

    Output:

        10
        2017-03-15T14:02:49.301000
        bar
        some_string
    
    0 讨论(0)
提交回复
热议问题