Dictionary comprehension with conditional
-
08-06-2021 - |
Question
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.
Solution
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.
OTHER TIPS
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}
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}
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}]
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}
Other way using lambda
(lambda x: {k:v for x in d.values() if type(x) == dict for k,v in x.items()})(d)