2011-03-21 67 views
40

我有持有对键/值Python列表:列表转换为每个键具有多个值的字典转换?

l=[ [1, 'A'], [1, 'B'], [2, 'C'] ] 

我要将列表转换成一个字典,其中每个键多个值将被汇总到一个元组:

{ 1:('A', 'B'), 2:('C',) } 

迭代解决方案很简单:

l=[ [1, 'A'], [1, 'B'], [2, 'C'] ] 
d={} 
for pair in l: 
    if d.has_key(pair[0]): 
     d[pair[0]]=d[pair[0]]+tuple(pair[1]) 
    else: 
     d[pair[0]]=tuple(pair[1]) 

print d 

{1: ('A', 'B'), 2: ('C',)} 

是否有完成这个任务,更优雅,Python的解决方案吗?

+1

S/multilpe /多 – vstrien 2011-03-21 13:36:24

+0

'has_key'是的道路上的垃圾箱Python历史记录 - 如果您必须测试字典中是否存在密钥,请使用新的语法“if key in dict:'。但是对于你的问题的“答案”是@ eumiro的defaultdict方法。 – PaulMcG 2011-03-21 13:43:58

+2

@vstrien谢谢。添加一个'/ g'会使它更通用:-) – 2011-03-21 13:51:57

回答

41
from collections import defaultdict 

d1 = defaultdict(list) 

for k, v in l: 
    d1[k].append(v) 

d = dict((k, tuple(v)) for k, v in d1.iteritems()) 

d现在包含{1: ('A', 'B'), 2: ('C',)}

d1是临时defaultdict使用列表作为值,这将在最后一行被转换为元组。这样你就可以追加到列表中而不会在主循环中重新创建元组。

+1

+1更好,这是一个新的工具。 – 2011-03-22 12:14:40

7

使用列表,而不是作为元组字典值:

l=[ [1, 'A'], [1, 'B'], [2, 'C'] ] 
d={} 
for key, val in l: 
    d.setdefault(key, []).append(val) 

print d 
2

的关键是已经排序在输入列表中?如果是这样的话,你有一个实用的解决方案:

import itertools 

lst = [(1, 'A'), (1, 'B'), (2, 'C')] 
dct = dict((key, tuple(v for (k, v) in pairs)) 
      for (key, pairs) in itertools.groupby(lst, lambda pair: pair[0])) 
print dct 
# {1: ('A', 'B'), 2: ('C',)} 
+0

如果你是'import operator',你可以写'itertools.groupby(sorted(lst),operator.itemgetter(0))' – eumiro 2011-03-21 14:25:04

+0

@eumiro。是的,我知道。请注意,在这里使用排序可能会改变所需的输出,这就是为什么我问他们是否已经排序(至少通过键)。 – tokland 2011-03-21 14:33:36

10

这种方法比较有效,相当紧凑:

reduce(lambda x, (k,v): x[k].append(v) or x, l, defaultdict(list)) 
+0

不错,但在python 3.5或更高版本中无效 – Davy 2017-05-15 19:42:35