20

I have some dictionaries of dictionaries, like this:

a['b']['c']['d']['answer'] = answer1
a['b']['c']['e']['answer'] = answer2
a['b']['c']['f']['answer'] = answer3
....
a['b']['c']['d']['conf'] = conf1
a['b']['c']['e']['conf'] = conf2
a['b']['c']['f']['conf'] = conf3

Is there a fast way to get a list of values of all answers for all elements at the third level (d,e,f)?

Specifically I'd like to know if there's any mechanism implementing a wildcard (e.g., a['b']['c']['*']['answer'].values()

update The fastest way I've found till now is:

[x['answer'] for x in a['b']['c'].values()]
redcrow
  • 1,743
  • 3
  • 25
  • 45
  • 2
    your solution in ``update`` is the best way to do it. ``dict`` in python is implemented as a hash-table. It actually doesn't know anything about the contents of its ``keys``, just their hash value. Therefore there'd be no way to sensicaly implement a wildcard, other than how you just did. Or, to put it another way, ``values()`` essentially already is the equivalent of ``'*'`` as a key (in the regex sense), and the rest of what you're trying to do is just list combinatorics. – aruisdante Jun 01 '14 at 16:01
  • Exactly, so nothing like that... :( Well, it would have been convenient. Anyway, thank you very much for your comment! – redcrow Jun 01 '14 at 16:07
  • 1
    Also, if you're in python 2.7, use ``itervalues`` instead of ``values``. The first returns a lazy-evaluated generator, whereas the second actually allocates a list. Python 3 turned ``values`` into ``itervalues`` and makes you do ``list(dict.values())`` to get a list back. – aruisdante Jun 01 '14 at 16:07

6 Answers6

29

In Python3 we can build a simple generator for this:

def NestedDictValues(d):
  for v in d.values():
    if isinstance(v, dict):
      yield from NestedDictValues(v)
    else:
      yield v

a={4:1,6:2,7:{8:3,9:4,5:{10:5},2:6,6:{2:7,1:8}}}
print(list(NestedDictValues(a)))

The output is:

[1, 2, 3, 4, 5, 6, 7, 8]

which is all of the values.

pippo1980
  • 2,181
  • 3
  • 14
  • 30
Richard
  • 56,349
  • 34
  • 180
  • 251
4

You could use a simple list comprehension:

[a['b']['c'][key]['answer'] for key in a['b']['c'].keys()]
Out[11]: ['answer1', 'answer2', 'answer3']

If you want to get all the answers and conf etc. You could do:

[[a['b']['c'][key][type] for key in a['b']['c'].keys()] for type in a['b']['c']['d'].keys()]
Out[15]: [['conf1', 'conf2', 'conf3'], ['answer1', 'answer2', 'answer3']]
Ankur Ankan
  • 2,953
  • 2
  • 23
  • 38
2

I would do that using recursive generator function:

def d_values(d, depth):
    if depth == 1:
        for i in d.values():
            yield i
    else:
        for v in d.values():
            if isinstance(v, dict):
                for i in d_values(v, depth-1):
                    yield i

Example:

>>> list(d_values({1: {2: 3, 4: 5}}, 2))
[3, 5]

In your case, this would give a dictionary like {'answer': answer1, 'conf': conf1} as each item, so you can use:

list(d['answer'] for d in d_values(a, 3))
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Not perfect for OP, but perfect for me. Small change, and its useful for getting all the last elements of a large nested dictionary – Roman May 24 '16 at 08:59
0

Just to give an answer to this topic, copying my solution from the "updating status" of my question:

[x['answer'] for x in a['b']['c'].values()]

Hope this can help.

redcrow
  • 1,743
  • 3
  • 25
  • 45
0
list(map(lambda key:  a['b']['c'][key],  a['b']['c'].keys()))
0

You can use a NestedDict. First, let me recreate your dictionary

>>> from ndicts.ndicts import NestedDict
>>> nd = NestedDict.from_product("b", "c", "def", ["answer", "conf"])
NestedDict({
    'b': {
        'c': {
            'd': {'answer': None, 'conf': None}, 
            'e': {'answer': None, 'conf': None}, 
            'f': {'answer': None, 'conf': None}
         }
     }
})

Then use an empty string as a wildcard

>>> nd_extract = nd.extract["b", "c", "", "answer"]
>>> nd_extract
NestedDict({
    'b': {
        'c': {
            'd': {'answer': None}, 
            'e': {'answer': None}, 
            'f': {'answer': None}
        }
    }
})

Finally get the values

>>> list(nd_extract.values())
[None, None, None]

To install ndicts

pip install ndicts
edd313
  • 1,109
  • 7
  • 20