字典列表到/从列表的字典


77

我希望在列表字典(长度相同)之间来回切换:

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

以及字典列表:

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

我正在寻找在两种形式之间切换的最简洁方法。


1
目前尚不清楚您将如何解释DL的顺序?即,如果您有很多元素,它们将失去其插入顺序。如果“ a”和“ b”以不同的顺序出现在DL中,那么所得LD的顺序应该是什么?
dawg

1
好的建议,德尔南和德鲁克,谢谢。我正在从CSV文件导入数据,其中列的顺序无关紧要。
亚当·格林霍尔

1
@AdamGreenhall,因为您正在使用CSV文件,所以我强烈建议您尝试一下熊猫。这有点像R类固醇上的数据框。
2014年

Answers:


13

也许考虑使用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

好漂亮 您能解释一下传递[(0,2),(1,3)][[0,2],[1,3]]到之间的区别np.array吗?具体来说,第二个为什么不起作用?
亚当·格林霍尔

@亚当格林霍尔:您在问一个很好的问题。我不知道完整的答案。我知道numpy有时会在列表和元组之间做出比Python大得多的区分。dtype语法的文档docs.scipy.org/numpy/docs/numpy.doc.structured_arrays表示,在使用“ [l] ist参数...定义dtype时……记录结构由元组列表定义”。但是我不知道为什么一定要这样。
unutbu 2011年

@unutbu谢谢,非常有趣。我没有听说过结构化数组。文档链接现已更改:numpy.org/doc/stable/user/basics.rec.html。另外,我在文档中注意到它说结构化数组“旨在与C代码进行接口并用于结构化缓冲区的低级操作……希望操纵表格数据(例如存储在csv文件中的用户)可能会找到其他pydata项目更合适的,例如xarray,pandas或DataArray。”
比尔

101

对于那些喜欢聪明/骇客的单线飞机的人。

这里是DLLD

v = [dict(zip(DL,t)) for t in zip(*DL.values())]
print(v)

LDDL

v = {k: [dic[k] for dic in LD] for k in LD[0]}
print(v)

LDDL由于您假设每个密钥都相同,所以to有点黑客dict。另外,请注意,我不容忍在任何实际系统中使用此类代码。


1
从LD到DL返回元组而不是列表,这可能会或可能不会更理想。顺便说一句,非常好用且方便的oneliners
theta

2
@GillBates你是正确的;LD-> DL代码依赖于所有命令以相同方式排序,这是一个可怕的假设。我已经替换了错误的代码。
阿兰·菲

要使用不同的键处理字典:LD [0]可以由reduce(set.union,[LD中D的set(D.keys()))]替换,如果LD中的k为dic的[dic [k] ],因此生成的一个线性为:v = {k:[如果dic中为k,则LD中dic的[dic [k]]对于reduce(set.union)中的k为k ])}
tozCSS

我确实喜欢聪明/机密的单缸飞机。我也认为这些是很好的解决方案,非常pythonic。他们使用了我认为python程序员应该熟悉的Python核心习语。
LudvigH

13

如果允许您使用外部软件包,Pandas可以很好地做到这一点:

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

哪个输出:

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

7
这可能是版本问题,但以上内容{'a': [0, 1], 'b': [2, 3]}以熊猫0.18.1返回。pd.DataFrame(DL).to_dict('records') 如描述的那样工作。
艾汉,2016年

12

要从词典列表中查找,很简单:

您可以使用以下形式:

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

走另一条路是有问题的。您需要从字典的键中获得一些有关插入顺序的信息。回想一下,字典中键的顺序不一定与原始插入顺序相同。

对于傻笑,假设插入顺序基于已排序的键。然后,您可以按照以下方式进行操作:

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

如果您的问题是基于好奇心,那么答案就是您。如果您遇到现实问题,请允许我建议您重新考虑数据结构。这些似乎都不是一个非常可扩展的解决方案。


8

这是我想出的一线解决方案(分布在多行上以提高可读性):

如果dl是列表的原始字典:

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

然后是将其转换为字典列表的方法:

ld = [{key:value[index] for key,value in dl.items()}
         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]))]

如果dl包含不对称列表,则可以正常工作:

from itertools import product

dl = {"a":[0, 1],"b":[2, 3, 4], "c":[5, 6, 7, 8]}

ld = [dict(zip(dl.keys(), items)) 
        for items in product(*(dl.values()))]

将其转换回列表字典的方法如下:

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而不是Python 3 functools.reduce

如果您假设列表中的所有字典都具有相同的键,则可以简化此操作:

dl2 = {key:[item[key] for item in ld] for key in ld[0].keys() }

1
回滚到版本4的意义是什么?请注意,您将第二个代码段中的范围设置为错误,并且删除python代码格式会使代码积极恶化。
Martin Bonner

5

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

谢谢@piRSquared将我介绍给cytoolz的世界。我的一生都在哪里?:)
Niklas B

4

的python模块pandas可以为您提供一个易于理解的解决方案。作为@chiang答案的补充,D对L和L对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

这是我的小脚本:

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)您假设清单的长度相同


1

我可以想到夏季星期五的最干净的方式。另外,它支持不同长度的列表(但在这种情况下,DLtoLD(LDtoDL(l))不再具有任何标识)。

  1. 从列表到字典

    实际上不如@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
    
  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

这是不使用任何库的解决方案:

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

0

如果您不介意发电机,可以使用类似

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

另一方面,我无法弄清您实际上要做什么。设计满足您要求的数据结构而不是试图将其插入现有数据结构中可能更为明智。(例如,字典列表是表示数据库查询结果的一种不好的方法。)


-4
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

1
嗨,安纳普(Anaup),能否请您解释一下一些解释?
KeyMaker00
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.