Reputation: 2086
Im trying to figure out how to get values from comprehension that is almost working. From this data ..
{'rock': {}, 'coal1': {'gold1': {'data': ['g1']}}, 'coal2': {'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}}
.. im trying to extract the gold key data into simple dict. i.e a dict of { gold : {'data' : [...]} }
items essentially ripping out the coal keys from the data.
in other words from this ..
{
"coal2": {
"gold3": {
"data": [
"g3"
]
},
"gold2": {
"data": [
"g2"
]
}
},
"coal1": {
"gold1": {
"data": [
"g1"
]
}
},
"rock": {}
}
to this format
{
"gold3": {
"data": [
"g3"
]
},
"gold1": {
"data": [
"g1"
]
},
"gold2": {
"data": [
"g2"
]
}
}
That is almost working. This gets rid of the rock.
>>> {k:d for k,d in data.items() if k != 'rock'}
{'coal2': {'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}, 'coal1': {'gold1': {'data': ['g1']}}}
And getting the values gets rid of the coal keys.
>>> [v for v in {k:d for k,d in data.items() if k != 'rock'}.values()]
[{'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}, {'gold1': {'data': ['g1']}}]
But i cant figure out how to get from this
>>> for i in [v for v in {k:d for k,d in data.items() if k != 'rock'}.values()] : print(i)
...
{'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}
{'gold1': {'data': ['g1']}}
to the desired structure. And it would be sweet if it could all be done with comprehensions. Does anyone know how to accomplish this ?
EDIT:
Both answers was amazing and I wish i could accept both. I like not importing anything but I accept @blhsing itertools version just because it is easier to comprehend and its a fraction better performance. BTW rock must be discarded even it has values so i could not bypass if k != 'rock'
. So here is the results and... Thanks guys.
>>> import timeit
>>> data = {'rock': {'type':'pebble'}, 'coal1': {'gold1': {'data': ['g1']}}, 'coal2': {'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}}
>>> timeit.timeit( "dict(kv for x in (v for v in {k:d for k,d in data.items() if k != 'rock'}.values()) for kv in x.items())" , setup="from __main__ import data")
2.6714617270044982
>>>
>>> timeit.timeit( "dict(chain.from_iterable(g.items() for g in {k:d for k,d in data.items() if k != 'rock'}.values()))" , setup="from __main__ import data; from itertools import chain")
2.22612579818815
>>>
Upvotes: 1
Views: 36
Reputation: 323226
Just need make your list
of dict
to dict
(Fixing you code with adding the second line)
l=[v for v in {k:d for k,d in d.items() if k != 'rock'}.values()] # here is your own code
newd=dict(kv for x in l for kv in x.items())
newd
Out[431]:
{'gold1': {'data': ['g1']},
'gold2': {'data': ['g2']},
'gold3': {'data': ['g3']}}
With one-line
dict(v for d in d.values() for v in d.items()) # d is your dict
Out[436]:
{'gold1': {'data': ['g1']},
'gold2': {'data': ['g2']},
'gold3': {'data': ['g3']}}
Upvotes: 1
Reputation: 106543
You can use a generator expression that outputs the items of the sub-dicts of the main dict's values, and use itertools.chain.from_iterable
to join the items, and pass them to the dict
constructor:
from itertools import chain
dict(chain.from_iterable(g.items() for g in d.values()))
so that given:
d = {'rock': {}, 'coal1': {'gold1': {'data': ['g1']}}, 'coal2': {'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}}}
this returns:
{'gold3': {'data': ['g3']}, 'gold2': {'data': ['g2']}, 'gold1': {'data': ['g1']}}
Upvotes: 1