我有两个清单:
alist = [11,12,13,11,15]
blist = ['A', 'A', 'B', 'A', 'B']
我想创建一个字典,其中blist中的项是键,而alist中的项是值,列表对应于两个列表中的索引:
结果应该是:
{'A': [11, 12, 11], 'B': [13, 15]}
我试过这个:
dictNames = {}
for i in xrange(len(alist)):
for letter in blist:
if letter not in dictNames:
dictNames[letter] = []
else:
dictNames[letter].append(alist[i])
给出了结果:
{'A': [11, 11, 12, 12, 12, 13, 13, 13, 11, 11, 11, 15, 15, 15], 'B': [11, 12, 12, 13, 13, 11, 11, 15, 15]}
为什么它不会附加到字典中预先存在的字母而不是在字典中已经添加到字母中?
答案 0 :(得分:6)
轻松使用defaultdict
:
from collections import defaultdict
dictNames = defaultdict(list)
for key, value in zip(blist, alist):
dictNames[key].append(value)
这会创建:
>>> dictNames
defaultdict(<type 'list'>, {'A': [11, 12, 11], 'B': [13, 15]})
defaultdict
是dict
的子类,所以它仍然可以像其他任何dict
一样工作。
如果没有defaultdict
,您必须测试该密钥是否已存在setdefault()
:
dictNames = {}
for key, value in zip(blist, alist):
dictNames.setdefault(key, []).append(value)
导致:
>>> dictNames
{'A': [11, 12, 11], 'B': [13, 15]}
这里的真正诀窍是使用zip()
来组合键和值列表而不是双循环。
答案 1 :(得分:2)
首先,循环遍历两个列表。对于alist中的每个项目,它都会通过blist循环。所以内循环运行25次。相反,您希望它运行5次,因此您只需要一个循环。
其次,如果列表尚不存在,则正确初始化列表,但在这种情况下,该数字不会添加到列表中。该号码应始终添加到列表中,即使它是新列表。
我更改了您的代码以考虑这两件事,并且它的效果更好一点:
for i in xrange(len(alist)):
letter = blist[i]
if letter not in dictNames:
dictNames[letter] = []
dictNames[letter].append(alist[i])
输出:
{'A': [11, 12, 11], 'B': [13, 15]}
答案 2 :(得分:0)
这种方式保留了订单
from collections import defaultdict
alist = [11,12,13,11,15]
blist = ['A', 'A', 'B', 'A', 'B']
d = defaultdict(list)
seen = defaultdict(set)
for k, v in zip(blist, alist):
if v not in seen[k]:
d[k].append(v)
seen[k].add(v)
print d
defaultdict(<type 'list'>, {'A': [11, 12], 'B': [13, 15]})
答案 3 :(得分:0)
这是一个单线解决方案:
{k: [alist[i] for i in range(len(blist)) if blist[i] == k] for k in set(blist)}
唯一的问题是,在最坏的情况下时间复杂度为O(n ^ 2),不适合大型列表。
答案 4 :(得分:0)
这是我目前可以提出的最短的表达方式:
from itertools import groupby
{k: {x[1] for x in v} for k, v in groupby(sorted(zip(blist, alist)), lambda x: x[0])}
相关(尚未提及)部分是对groupby
的调用,也在以下类似问题中进行了描述:Python group by