Reputation: 1166
I believe this is not so easy to explain with words but with an example it should be pretty clear.
Suppose I have the dictionaries link_vars
and y
:
link_vars = {'v1':'AAA', 'v2':'BBB', 'v3':'CCC'}
y = {'v1':[1,2,3], 'v2':[4,5,6], 'v3':[7,8,9]}
And I want to build the list desired_output
:
desired_output = [{'AAA':1 , 'BBB':4, 'CCC':7},
{'AAA':2 , 'BBB':5, 'CCC':8},
{'AAA':3 , 'BBB':6, 'CCC':9}]
So, basically, I want to 'translate' the keys in y
according to the entries of the dictionary link_vars
, and then split the lists in y
into small dictionaries to build desired_output
. The keys of y
and link_vars
will always be the same, and the length of each list in the values of y
will be the same as well (i.e. there will not be a list with 4 elements and another one with 5).
I'm not being able to think of a smart way to do this. I hope there is an efficient way to do this, as the length of the output list (which is the same as the lengths of each list in the values of y
) can be pretty large.
Upvotes: 2
Views: 47
Reputation: 164693
Here's a solution which links the two dictionaries:
from operator import itemgetter
keys = itemgetter(*y)(link_vars)
res = [dict(zip(keys, v)) for v in zip(*y.values())]
[{'AAA': 1, 'BBB': 4, 'CCC': 7},
{'AAA': 2, 'BBB': 5, 'CCC': 8},
{'AAA': 3, 'BBB': 6, 'CCC': 9}]
Explanation
keys
, which extracts values from link_vars
in an order which is consistent with the keys from y
.zip
the pre-calculated keys
with a transposed version of y.values()
. We assume y.values()
iterates consistently with y.keys()
, which is true in Python 2.x and 3.x.Upvotes: 3
Reputation: 18916
Ok fine then. A list comprehension should do in this case:
output = [dict(zip(link_vars.values(),i)) for i in zip(*y.values())]
print(output)
Returns:
[{'AAA': 1, 'BBB': 4, 'CCC': 7},
{'AAA': 2, 'BBB': 5, 'CCC': 8},
{'AAA': 3, 'BBB': 6, 'CCC': 9}]
Taking in consideration jpps comment, maybe a more appropriate approach would be to first make sure that we get the right values by merging the dicts together.
temp_d = {v:y.get(k) for k,v in link_vars.items()}
output = [dict(zip(temp_d.keys(),i)) for i in zip(*temp_d.values())]
Or using pandas library, might be overkill, but the syntax is easy to understand as we only need to merge the dicts and handle the rest with to_dict()
func.
import pandas as pd
output = pd.DataFrame({v:y.get(k) for k,v in link_vars.items()}).to_dict('r')
Explanation
The key idea here is to zip together the values of y. This is done with zip(*y.values())
. And running the list comprehension: [i for i in zip(*y.values())]
which equals [(7, 4, 1), (8, 5, 2), (9, 6, 3)]
the remaining part is to zip together each component with AAA,BBB,CCC
.
Upvotes: 2