简体   繁体   中英

How to create a list of dictionaries from a dictionary with lists of different lengths

I want to create a list of dictionaries with the same index element from each list.

I have this dictionary:

d = {'name': ['bob', 'john', 'harry', 'mary'], 
     'age': [13, 19, 23], 
     'height': [164, 188], 
     'job': ['programmer']}

The desired output is:

d2 = [{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}, 
      {'name': 'john', 'age': 19, 'height': 188}, 
      {'name': 'harry', 'age': 23},
      {'name': 'mary'}]

I have tried something like this:

d2 = [dict(zip(d, t)) for t in zip(*d.values())]

But my output is:

d2 = [{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}]

I think this is happening because the lists have different lengths.

You can use itertools.zip_longest and filter out None values:

from itertools import zip_longest

[{x: y for x, y in zip(d, t) if y is not None} for t in zip_longest(*d.values())]
# [{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}, 
#  {'name': 'john', 'age': 19, 'height': 188}, 
#  {'name': 'harry', 'age': 23}, 
#  {'name': 'mary'}]

You can use zip_longest here:

from itertools import zip_longest

keys = d.keys()

d2 = [
    {k: v for k, v in zip(keys, vs) if v is not None}
    for vs in 
]

If the values can be None as well, we can circumvent that by using a dummy value:

from itertools import zip_longest

keys = d.keys()
dummy = object()

d2 = [
    {k: v for k, v in zip(keys, vs) if v is not dummy}
    for vs in 
]

Here the dummy is an object which we are sure that is not part of the items in d (since we construct it after we constructed d ). By using an is comparison, we thus can know if that value was the "fillvalue".

This will give us:

>>> d2
[{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}, {'name': 'john', 'age': 19, 'height': 188}, {'name': 'harry', 'age': 23}, {'name': 'mary'}]

Here is another approach :

d = {'name': ['bob', 'john', 'harry', 'mary'], 'age': [13, 19, 23], 'height': [164, 188], 'job': ['programmer']}
m = max(map(len, d.values()))
d1 = {k : (v if len(v)==m else v+['']*(m-len(v))) for k,v in d.items()}
d2 = [{k:v for k,v in zip(d, t) if v} for t in zip(*d1.values())]
print(d2)

Output :

[{'height': 164, 'age': 13, 'job': 'programmer', 'name': 'bob'}, {'height': 188, 'age': 19, 'name': 'john'}, {'age': 23, 'name': 'harry'}, {'name': 'mary'}]

A simple solution without using zip_longest, for the record:

d = {'name': ['bob', 'john', 'harry', 'mary'], 'age': [13, 19, 23], 'height': [164, 188], 'job': ['programmer']}

recordset = [{k: v[i] for k, v in d.items() if i < len(v)} for i in range(max([len(l) for l in d.values()]))]

print(recordset)  # >> [{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}, 
                        {'name': 'john', 'age': 19, 'height': 188}, 
                        {'name': 'harry', 'age': 23}, 
                        {'name': 'mary'}]

Just keep everything and add this import statement:

from itertools import zip_longest as zip

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