Как создать список словарей из словаря со списками разной длины
Я хочу создать список словарей с тем же элементом индекса из каждого списка.
У меня есть этот словарь:
d = {'name': ['bob', 'john', 'harry', 'mary'],
'age': [13, 19, 23],
'height': [164, 188],
'job': ['programmer']}
Желаемый результат:
d2 = [{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'},
{'name': 'john', 'age': 19, 'height': 188},
{'name': 'harry', 'age': 23},
{'name': 'mary'}]
Я пробовал что-то вроде этого:
d2 = [dict(zip(d, t)) for t in zip(*d.values())]
Но мой вывод:
d2 = [{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}]
Я думаю, что это происходит потому, что списки имеют разную длину.
Ответы
Ответ 1
Вы можете использовать itertools.zip_longest
и отфильтровать значения None
:
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'}]
Ответ 2
Вы можете использовать zip_longest
здесь:
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 zip_longest(*d.values())
]
Если значения также могут быть None
, мы можем обойти это, используя фиктивное значение:
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 zip_longest(*d.values(), fillvalue=dummy)
]
Здесь манекен - это объект, который, как мы уверены, не является частью элементов в d
(поскольку мы создаем его после того, как мы построили d
). Используя сравнение is
, мы можем узнать, было ли это значение "fillvalue".
Ти даст нам:
>>> d2
[{'name': 'bob', 'age': 13, 'height': 164, 'job': 'programmer'}, {'name': 'john', 'age': 19, 'height': 188}, {'name': 'harry', 'age': 23}, {'name': 'mary'}]
Ответ 3
Вот другой подход:
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)
Вывод :
[{'height': 164, 'age': 13, 'job': 'programmer', 'name': 'bob'}, {'height': 188, 'age': 19, 'name': 'john'}, {'age': 23, 'name': 'harry'}, {'name': 'mary'}]
Ответ 4
Простое решение без использования zip_longest, для записи:
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'}]
Ответ 5
Просто сохраните все и добавьте это утверждение импорта:
из itertools импортируйте zip_longest как zip