Список диктов в/из диктов списков
Я хочу переключаться между словарями списков (одинаковой длины):
DL = {'a': [0, 1], 'b': [2, 3]}
и список словарей:
LD = [{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
Я ищу самый чистый способ переключения между двумя формами.
Ответы
Ответ 1
Возможно, стоит подумать об использовании numpy:
import numpy as np
arr = np.array([(0, 2), (1, 3)], dtype=[('a', int), ('b', int)])
print(arr)
# [(0, 2) (1, 3)]
Здесь мы получаем доступ к столбцам, индексированным по именам, например, 'a'
или 'b'
(вроде как DL
):
print(arr['a'])
# [0 1]
Здесь мы получаем доступ к строкам по целочисленному индексу (вроде как LD
):
print(arr[0])
# (0, 2)
К каждому значению в строке можно получить доступ по имени столбца (вроде как LD
):
print(arr[0]['b'])
# 2
Ответ 2
Для тех из вас, кто любит умные/хакерские реплики.
Вот DL
- LD
:
v = [dict(zip(DL,t)) for t in zip(*DL.values())]
print(v)
и LD
- DL
:
v = {k: [dic[k] for dic in LD] for k in LD[0]}
print(v)
LD
- DL
немного хакер, так как вы предполагаете, что ключи одинаковы в каждом dict
. Также обратите внимание, что я не одобряю использование такого кода в любой реальной системе.
Ответ 3
Чтобы перейти из списка словарей, это просто:
Вы можете использовать эту форму:
DL={'a':[0,1],'b':[2,3], 'c':[4,5]}
LD=[{'a':0,'b':2, 'c':4},{'a':1,'b':3, 'c':5}]
nd={}
for d in LD:
for k,v in d.items():
try:
nd[k].append(v)
except KeyError:
nd[k]=[v]
print nd
#{'a': [0, 1], 'c': [4, 5], 'b': [2, 3]}
Или используйте defaultdict:
nd=cl.defaultdict(list)
for d in LD:
for key,val in d.items():
nd[key].append(val)
print dict(nd.items())
#{'a': [0, 1], 'c': [4, 5], 'b': [2, 3]}
Переход на другую сторону проблематичен. Вы должны иметь некоторую информацию о порядке вставки в списке из ключей из словаря. Напомним, что порядок ключей в dict не обязательно совпадает с порядком ввода.
Для хихиканья предположим, что порядок вставки основан на отсортированных клавишах. Затем вы можете сделать это следующим образом:
nl=[]
nl_index=[]
for k in sorted(DL.keys()):
nl.append({k:[]})
nl_index.append(k)
for key,l in DL.items():
for item in l:
nl[nl_index.index(key)][key].append(item)
print nl
#[{'a': [0, 1]}, {'b': [2, 3]}, {'c': [4, 5]}]
Если ваш вопрос был основан на любопытстве, есть ваш ответ. Если у вас есть реальная проблема, позвольте мне предложить вам пересмотреть свои структуры данных. Ни один из них не является очень масштабируемым решением.
Ответ 4
Если вам разрешено использовать внешние пакеты, Pandas отлично работает для этого:
import pandas as pd
pd.DataFrame(DL).to_dict('list')
Какие выходы:
[{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
Ответ 5
Вот однолинейные решения (разбросанные по нескольким строкам для удобочитаемости), которые я придумал:
если dl - ваш исходный список списков:
dl = {"a":[0,1],"b":[2,3]}
Затем здесь, как преобразовать его в список dicts:
ld = [{key:value[index] for key in dl.keys()}
for index in range(max(map(len,dl.values()]
Что, если вы предполагаете, что все ваши списки имеют одинаковую длину, вы можете упростить и увеличить производительность, перейдя к:
ld = [{key:value[index] for key, value in dl.items()}
for index in range(len(dl.values()[0]))]
и здесь, как преобразовать это обратно в список списков:
dl2 = {key:[item[key] for item in ld]
for key in list(functools.reduce(
lambda x, y: x.union(y),
(set(dicts.keys()) for dicts in ld)
))
}
Если вы используете Python 2 вместо Python 3, вы можете просто использовать reduce
вместо functools.reduce
.
Вы можете упростить это, если предположите, что все dicts в вашем списке будут иметь одинаковые ключи:
dl2 = {key:[item[key] for item in ld] for key in ld[0].keys() }
Ответ 6
cytoolz.dicttoolz.merge_with
Документы
from cytoolz.dicttoolz import merge_with
merge_with(list, *LD)
{'a': [0, 1], 'b': [2, 3]}
Версия без Cython
Документы
from toolz.dicttoolz import merge_with
merge_with(list, *LD)
{'a': [0, 1], 'b': [2, 3]}
Ответ 7
Модуль python в pandas
может дать вам простое для понимания решение. В дополнение к ответу @chiang решения D-to-L и L-to-D следующие:
In [1]: import pandas as pd
In [2]: DL = {'a': [0, 1], 'b': [2, 3]}
In [3]: pd.DataFrame(DL).to_dict('records')
Out[3]: [{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
In [4]: LD = [{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
In [5]: pd.DataFrame(LD).to_dict('list')
Out[5]: {'a': [0, 1], 'b': [2, 3]}
Ответ 8
Здесь мой маленький script:
a = {'a': [0, 1], 'b': [2, 3]}
elem = {}
result = []
for i in a['a']: # (1)
for key, value in a.items():
elem[key] = value[i]
result.append(elem)
elem = {}
print result
Я не уверен, что это прекрасный способ.
(1) Предположим, что у вас одинаковая длина для списков
Ответ 9
Самый чистый способ я могу думать о летней пятнице. В качестве бонуса он поддерживает списки разной длины (но в этом случае DLtoLD(LDtoDL(l))
больше не идентичен).
-
Из списка в dict
На самом деле менее чистая, чем версия @dwerk defaultdict.
def LDtoDL (l) :
result = {}
for d in l :
for k, v in d.items() :
result[k] = result.get(k,[]) + [v] #inefficient
return result
-
От dict до списка
def DLtoLD (d) :
if not d :
return []
#reserve as much *distinct* dicts as the longest sequence
result = [{} for i in range(max (map (len, d.values())))]
#fill each dict, one key at a time
for k, seq in d.items() :
for oneDict, oneValue in zip(result, seq) :
oneDict[k] = oneValue
return result
Ответ 10
Вот решение без использования каких-либо библиотек:
def dl_to_ld(initial):
finalList = []
neededLen = 0
for key in initial:
if(len(initial[key]) > neededLen):
neededLen = len(initial[key])
for i in range(neededLen):
finalList.append({})
for i in range(len(finalList)):
for key in initial:
try:
finalList[i][key] = initial[key][i]
except:
pass
return finalList
Вы можете назвать это следующим образом:
dl = {'a':[0,1],'b':[2,3]}
print(dl_to_ld(dl))
#[{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
Ответ 11
Если вы не возражаете против генератора, вы можете использовать что-то вроде
def f(dl):
l = list((k,v.__iter__()) for k,v in dl.items())
while True:
d = dict((k,i.next()) for k,i in l)
if not d:
break
yield d
Это не так "чисто", как это могло бы быть из-за технических причин: моя первоначальная реализация сделала yield dict(...)
, но в конечном итоге это пустой словарь, потому что (в Python 2.5) a for b in c
не различает исключение StopIteration, когда итерация по c
и исключение StopIteration при оценке a
.
С другой стороны, я не могу понять, что вы на самом деле пытаетесь сделать; возможно, было бы более разумно проектировать структуру данных, которая соответствует вашим требованиям, вместо того, чтобы пытаться привязать ее к существующим структурам данных. (Например, список dicts - это плохой способ представления результата запроса к базе данных.)
Ответ 12
DL={'a':[0,1,2,3],'b':[2,3,4,5]}
LD=[{'a':0,'b':2},{'a':1,'b':3}]
Empty_list = []
Empty_dict = {}
# to find length of list in values of dictionry
len_list = 0
for i in DL.values():
if len_list < len(i):
len_list = len(i)
for k in range(len_list):
for i,j in DL.items():
Empty_dict[i] = j[k]
Empty_list.append(Empty_dict)
Empty_dict = {}
LD = Empty_list