Tendero
Tendero

Reputation: 1166

Translate information of two dictionaries into a list of dictionaries

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

Answers (2)

jpp
jpp

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

  1. First, define keys, which extracts values from link_vars in an order which is consistent with the keys from y.
  2. Second, use a list comprehension and 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

Anton vBR
Anton vBR

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

Related Questions