0

What is the most Pythonic way to convert this:

{'a': ['apple1', 'apple2', 'apple3'], 'b': ['banana1', 'banana2', 'banana3']}

into this?

[{'a': 'apple1', 'b': 'banana1'}, {'a': 'apple2', 'b': 'banana2'}, {'a': 'apple3', 'b': 'banana3'}]

I would prefer a solution that doesn't use array comprehensions.

This is my current approach

d = {
    'a': ['apple1', 'apple2', 'apple3'],
    'b': ['banana1', 'banana2', 'banana3']
}

r = []
for k,v in d.items():
    for i in range(len(v)):
        if len(r) <= i:
            r.append({})
        r[i][k] = v[i]
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Jorjon
  • 5,316
  • 1
  • 41
  • 58

1 Answers1

3

You can use the following approach:

[dict(zip(d.keys(),vs)) for vs in zip(*d.values())]

With d the original dictionary.

This generates:

>>> [dict(zip(d.keys(),vs)) for vs in zip(*d.values())]
[{'b': 'banana1', 'a': 'apple1'}, {'b': 'banana2', 'a': 'apple2'}, {'b': 'banana3', 'a': 'apple3'}]

The code works as follows, it is guaranteed that - given a dictionary is not changed - d.keys() and d.values() generate the keys/values in the same order: so you can dict(zip(d.keys(),d.values())) back into the original dictionary.

Now what we do is we make a transpose of the .values() of the dictionary, by using zip(*d.values()). For each such "column" (of the tranpose), we zip the column with the d.keys() and convert that into a dictionary (with dict(..)), by using list comprehension, we will eventually iterate over all rows.

Mind that the iteration stops from the moment one of the lists in the values is exhausted.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555