Я хочу переключаться между словарями списков (одинаковой длины):
DL = {'a': [0, 1], 'b': [2, 3]}
и список словарей:
LD = [{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
Я ищу самый чистый способ переключения между двумя формами.
Я хочу переключаться между словарями списков (одинаковой длины):
DL = {'a': [0, 1], 'b': [2, 3]}
и список словарей:
LD = [{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
Я ищу самый чистый способ переключения между двумя формами.
Возможно, стоит подумать об использовании 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
Для тех из вас, кто любит умные/хакерские реплики.
Вот 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
. Также обратите внимание, что я не одобряю использование такого кода в любой реальной системе.
Чтобы перейти из списка словарей, это просто:
Вы можете использовать эту форму:
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]}]
Если ваш вопрос был основан на любопытстве, есть ваш ответ. Если у вас есть реальная проблема, позвольте мне предложить вам пересмотреть свои структуры данных. Ни один из них не является очень масштабируемым решением.
Если вам разрешено использовать внешние пакеты, Pandas отлично работает для этого:
import pandas as pd
pd.DataFrame(DL).to_dict('list')
Какие выходы:
[{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
Вот однолинейные решения (разбросанные по нескольким строкам для удобочитаемости), которые я придумал:
если 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() }
cytoolz.dicttoolz.merge_with
from cytoolz.dicttoolz import merge_with
merge_with(list, *LD)
{'a': [0, 1], 'b': [2, 3]}
from toolz.dicttoolz import merge_with
merge_with(list, *LD)
{'a': [0, 1], 'b': [2, 3]}
Модуль 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]}
Здесь мой маленький 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) Предположим, что у вас одинаковая длина для списков
Самый чистый способ я могу думать о летней пятнице. В качестве бонуса он поддерживает списки разной длины (но в этом случае 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
Вот решение без использования каких-либо библиотек:
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}]
Если вы не возражаете против генератора, вы можете использовать что-то вроде
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 - это плохой способ представления результата запроса к базе данных.)
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