список диктов в / из диктов списков - PullRequest
50 голосов
/ 06 апреля 2011

Я хочу переключаться между словарем списков (все одинаковой длины):

DL={'a':[0,1],'b':[2,3]}

и списком словарей:

LD=[{'a':0,'b':2},{'a':1,'b':3}]

Я являюсьищу самый чистый способ переключения между двумя формами.

Ответы [ 12 ]

52 голосов
/ 09 октября 2015

Для тех из вас, кто любит умные / хакерские однострочники.

Здесь 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. Также обратите внимание, что я не одобряю использование такого кода в любой реальной системе.

12 голосов
/ 06 апреля 2011

Чтобы перейти от списка словарей, это просто:

Вы можете использовать эту форму:

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]}]

Если ваш вопрос был основан на любопытстве, то ваш ответ есть.Если у вас есть реальные проблемы, позвольте мне предложить вам пересмотреть свои структуры данных.Ни один из них, кажется, не является очень масштабируемым решением.

10 голосов
/ 08 августа 2014

Если вам разрешено использовать внешние пакеты, Pandas отлично подходит для этого:

import pandas as pd
pd.DataFrame(DL).to_dict('list')

Какие выходы:

[{'a': 0, 'b': 2}, {'a': 1, 'b': 3}]
8 голосов
/ 06 апреля 2011

Возможно рассмотрите возможность использования 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
5 голосов
/ 09 мая 2014

Вот однострочные решения (разбросанные по нескольким строкам для удобства чтения), которые я придумала:

, если dl - ваш исходный набор списков:

dl = {"a":[0,1],"b":[2,3]}

Тогдавот как преобразовать его в список диктов:

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 Там.

Вы можете упростить это, если предположите, что все диктанты в вашем списке будут иметь одинаковые ключи:

dl2 = {key:[item[key] for item in ld] for key in ld[0].keys() }
4 голосов
/ 09 октября 2018

cytoolz.dicttoolz.merge_with

Docs

from cytoolz.dicttoolz import merge_with

merge_with(list, *LD)

{'a': [0, 1], 'b': [2, 3]}

Версия без Cython

Docs

from toolz.dicttoolz import merge_with

merge_with(list, *LD)

{'a': [0, 1], 'b': [2, 3]}
2 голосов
/ 01 мая 2018

Модуль 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]}
1 голос
/ 22 февраля 2019

Вот решение без использования каких-либо библиотек:

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}]
1 голос
/ 10 августа 2012

Самый чистый способ думать о летней пятнице.В качестве бонуса он поддерживает списки различной длины (но в этом случае DLtoLD(LDtoDL(l)) больше не идентичность).

  1. От списка к диктату

    На самом деле менее чисточем версия по умолчанию @ dwerk.

    def LDtoDL (l) :
       result = {}
       for d in l :
          for k, v in d.items() :
             result[k] = result.get(k,[]) + [v] #inefficient
       return result
    
  2. От дикта к списку

    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
    
1 голос
/ 06 апреля 2011

Вот мой маленький скрипт:

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) Вы полагаете, что у вас одинаковая длина списков

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...