3

So I'm wondering if anyone can help me out with this issue I'm having.

Lets assume I have a dictionary:

d = {1: {2: 3}, 4: 5}

I want to create a dictionary of any contained dictionaries:

wanted_result = {2: 3}

what I am trying is this:

e = {inner_key: d[key][inner_key] for key in d.keys() for inner_key in d[key].keys() if isinstance(d[key], dict)}

However this is causing me to get an error saying that ints don't have keys, which I know, but I thought my conditional would exclude say 4 from my example from being included in the comprehension.

Wooble
  • 87,717
  • 12
  • 108
  • 131
spdub
  • 45
  • 1
  • 5
  • 2
    What should the result be if there is more than one nested dict? What if they are nested more deeply? – Tim Pietzcker May 11 '12 at 21:10
  • say started at d = {1: {2: {3: 4}, 5: 6}, 7: 8}, would just assume to get {2: {3: 4}, 5: 6} . ie only gathering the dictionaries one layer deep – spdub May 11 '12 at 21:21

6 Answers6

10
d = {1: {2: 3}, 4: 5, 6: {7: 8}}
s = {k: v for elem in d.values() if type(elem) is dict for k, v in elem.items()}
>> {2: 3, 7: 8}
georg
  • 211,518
  • 52
  • 313
  • 390
2

In this case, I would recommend you a for-loop and the update method:

d = {1: {2: 3}, 4: 5, 6: {7: 8}}
inner_dicts = {}
for val in d.values():
    if type(val) is dict:
        inner_dicts.update(val)
print inner_dicts
# {2: 3, 7: 8}
juliomalegria
  • 24,229
  • 14
  • 73
  • 89
1

The following list comprehension will return each value that is a dict:

>>> d = {1: {2: 3}, 4: 5}
>>> [d[i] for i in d.keys() if isinstance(d[i],dict)]
[{2: 3}]
garnertb
  • 9,454
  • 36
  • 38
1
d = {1: {2: 3}, 4: 5,'j':{7:8}}
e={y:d[x][y] for x in d if isinstance(d[x],dict) for y in d[x]}
print(e)

{2: 3, 7: 8}
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
1

My first idea was something like this:

d = {1: {2: 3}, 4: 5, 6: {7: 8}}
generator = (x.items() for x in d.itervalues() if type(x) == dict)
s = dict(sum( generator, list() )) 
# s = {2: 3, 7: 8}

But, in order to avoid letting sum() construct a large temporary list of all the items() you may use itertools.chain and iteritems() instead:

# chain "concatenates" iterables
from itertools import chain
d = {1: {2: 3}, 4: 5, 6: {7: 8}}
s = dict(chain( *(x.iteritems() for x in d.itervalues() if type(x) == dict) ))
# s = {2: 3, 7: 8}

You should be aware of edge cases. Especially if identical keys are in the part-dictionaries these will necessarily collapse somehow.


If you also want to support subclasses of dict to be collected from your d.values(), you may indeed want to use isinstance instead of type. See this question for details.

Community
  • 1
  • 1
moooeeeep
  • 31,622
  • 22
  • 98
  • 187
  • Why in earth did you choose `_` as your variable name? (http://stackoverflow.com/a/1739541/972208) – juliomalegria May 11 '12 at 21:20
  • @julio.alegria I used this occasionally for temporary variables (be sure to not shadow another `x`). Wasn't aware of the special semantics in interactive mode though! – moooeeeep May 11 '12 at 21:25
0

Other way using lambda

(lambda x: {k:v for x in d.values() if type(x) == dict for k,v in x.items()})(d)

Mirage
  • 30,868
  • 62
  • 166
  • 261