简体   繁体   中英

Converting a dictionary with lists into a list of dictionaries

I have this dictionary containing lists as they're values for keys.

d = {'n': ['a', 'b', 'x'], 'a': [1, 2, 3], 'p': ['123', '321', '456']}

And I want to convert into a list of dictionary as such

[{'n': 'a', 'a': 1, 'p': '123'}, {'n': 'b', 'a': 2, 'p': '321'}, {'n': 'x', 'a': 3, 'p': '456'}]

My current solution is,

the_kv = d.items()
f = {}
c = {}
e = {}

f_c_e = []
for i, j in the_kv:
    f[i] = j[0]
    c[i] = j[1]
    e[i] = j[2]

f_c_e.append(f)
f_c_e.append(c)
f_c_e.append(e)
print(f_c_e)

But I was wondering if there is a more efficient way rather than creating separate dicts and then appending them to a list.

Using zip :

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

Result:

[{'n': 'a', 'a': 1, 'p': '123'}, {'n': 'b', 'a': 2, 'p': '321'}, {'n': 'x', 'a': 3, 'p': '456'}]

Use:

res = [dict(v) for v in zip(*[[(key, value) for value in values] for key, values in d.items()])]
print(res)

Output

[{'n': 'a', 'a': 1, 'p': '123'}, {'n': 'b', 'a': 2, 'p': '321'}, {'n': 'x', 'a': 3, 'p': '456'}]

A simpler alternative approach is to do:

result = [{} for _ in range(len(d))]
for key, values in d.items():
    for i, value in enumerate(values):
        result[i][key] = value

print(result)

Output (alternative)

[{'n': 'a', 'a': 1, 'p': '123'}, {'n': 'b', 'a': 2, 'p': '321'}, {'n': 'x', 'a': 3, 'p': '456'}]

Good Question. Conversion from one data type to other is essential in either development or competitive programming.

It can be done in many methods, I'm explaining the two methods which I know, below:

Method #1 : Using list comprehension We can use list comprehension as the one-liner alternative to perform various naive tasks providing readability with a more concise code. We can iterate through each of dictionary element and corresponding keep constructing the list of dictionary.

# Python3 code to demonstrate 
# to convert dictionary of list to 
# list of dictionaries
# using list comprehension
  
# initializing dictionary
test_dict = { "Rash" : [1, 3], "Manjeet" : [1, 4], "Akash" : [3, 4] }
  
# printing original dictionary
print ("The original dictionary is : " + str(test_dict))
  
# using list comprehension
# to convert dictionary of list to 
# list of dictionaries
res = [{key : value[i] for key, value in test_dict.items()}
         for i in range(2)]
  
# printing result
print ("The converted list of dictionaries " +  str(res))

Method #2 : Using zip() This approach used zip function two times, first time when we need to zip the particular index value of all lists as one and second to get all values of particular index and zip it with the corresponding keys.

# Python3 code to demonstrate
# to convert dictionary of list to
# list of dictionaries
# using zip()

# initializing dictionary
test_dict = { "Rash" : [1, 3], "Manjeet" : [1, 4], "Akash" : [3, 4] }

# printing original dictionary
print ("The original dictionary is : " + str(test_dict))

# using zip()
# to convert dictionary of list to
# list of dictionaries
res = [dict(zip(test_dict, i)) for i in zip(*test_dict.values())]

# printing result
print ("The converted list of dictionaries " + str(res))

Output

The original dictionary is : {‘Rash’: [1, 3], ‘Manjeet’: [1, 4], ‘Akash’: [3, 4]}
The converted list of dictionaries [{‘Rash’: 1, ‘Manjeet’: 1, ‘Akash’: 3}, {‘Rash’: 3, ‘Manjeet’: 4, ‘Akash’: 4}]

Let's work through the problem step by step.

The core difficulty is that we have a sequence of lists:

['a', 'b', 'x']
[1, 2, 3]
['123', '321', '456']

And we want to produce sequences consisting of element 0 of each list, element 1 of each list, etc. (Each of these sequences contains all the values for an output dict.) Which is to say, we want to transpose the lists, which is exactly what the built-in zip is for:

# Feed the generator to `list` to unpack and view them
list(zip(
    ['a', 'b', 'x'],
    [1, 2, 3],
    ['123', '321', '456']
))

Now we can sketch out a complete process:

  1. Get the keys and values of the input (in the same order).
  2. Transpose the values.
  3. For each sequence in the transposed values, match that sequence up with the keys to make a new dict.

The first two parts are easy:

keys, value_lists = d.keys(), d.values()
# Since the .values() are a sequence, while `zip` accepts multiple
# arguments, we need to use the `*` operator to unpack them as
# separate arguments.
grouped_values = zip(*value_lists)

To finish up, let's first figure out how to create a single result dict from a single one of the new_values . It's easy to make a dict from a bunch of key-value pairs - we can feed that directly to dict . However, we have instead a pair of sequences - the original .keys() , and a result from the zip . Clearly, the solution is to zip again - we can make a trivial helper function to make sure everything is as clear as possible:

def new_dict(keys, values):
    return dict(zip(keys, values))

Then all we need to do is repeatedly apply that function :

new_dicts = [new_dict(keys, values) for values in grouped_values]

Putting everything inline with short names for the sake of showing off gives:

new_dicts = [dict(zip(d.keys(), v)) for v in zip(*d.values())]

which is almost exactly Jab's answer (note that iterating over a dictionary gives the keys, so you can pass d directly rather than d.keys() to zip since zip will only be iterating over it).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM