简体   繁体   English

使用索引从两个列表中制作字典

[英]making a dictionary from two lists using indices

I have two lists: 我有两个清单:

alist =  [11,12,13,11,15]
blist = ['A', 'A', 'B', 'A', 'B']

I want to make a dictionary where items in blist are keys and items in alist are values with lists corresponding to indices in the two lists: 我想制作一个字典,其中blist中的项是键,而alist中的项是值,其值与两个列表中的索引相对应:

the outcome should be: 结果应该是:

{'A': [11, 12, 11], 'B': [13, 15]}

I have tried this: 我已经试过了:

dictNames = {}
for i in xrange(len(alist)):
    for letter in blist:
        if letter not in dictNames:
            dictNames[letter] = []
        else:
            dictNames[letter].append(alist[i])

which gives the outcome: 结果如下:

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

Why does it not append to the pre-existing letter in the dictionary instead of adding to it when it is already in the dictionary? 为什么它不附加在字典中的现有字母上,而不是添加到字典中已有的字母上?

Use a defaultdict for ease: 轻松使用defaultdict

from collections import defaultdict

dictNames = defaultdict(list)
for key, value in zip(blist, alist):
    dictNames[key].append(value)

This creates: 这将创建:

>>> dictNames
defaultdict(<type 'list'>, {'A': [11, 12, 11], 'B': [13, 15]})

defaultdict is a subclass of dict so it'll still work just like any other dict . defaultdictdict的子类,因此它仍然可以像其他dict一样工作。

Without defaultdict you'll have to test if the key is already present with setdefault() : 如果没有defaultdict ,则必须使用setdefault()测试密钥是否已经存在:

dictNames = {}
for key, value in zip(blist, alist):
    dictNames.setdefault(key, []).append(value)

resulting in: 导致:

>>> dictNames
{'A': [11, 12, 11], 'B': [13, 15]}

The real trick here is using zip() to combine your key and value lists instead of your double loops. 真正的窍门是使用zip()组合键和值列表,而不是双循环。

First, you loop over both lists. 首先,您遍历两个列表。 For every item in alist, it loops through blist. 对于列表中的每个项目,它都会遍历blist。 So the inner loop runs 25 times. 因此,内部循环运行25次。 Instead, you want it to run 5 times, so you want only one loop. 相反,您希望它运行5次,因此只需要一个循环。

Second, you correctly initialize the list if it does not yet exist, but in that case the number is not added to the list. 其次,如果该列表尚不存在,则可以正确地对其进行初始化,但是在这种情况下,该数字不会添加到列表中。 The number should always be added to the list, even if it is a new list. 该号码应始终添加到列表中,即使它是新列表也是如此。

I changed your code to take these two things into account, and it works a little better: 我更改了您的代码以考虑到这两点,并且效果更好:

for i in xrange(len(alist)):
    letter = blist[i]
    if letter not in dictNames:
        dictNames[letter] = []
    dictNames[letter].append(alist[i])

Output: 输出:

{'A': [11, 12, 11], 'B': [13, 15]}

This way preserves order 这样可以保持秩序

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

Here is a one-line solution: 这是一线解决方案:

 {k: [alist[i] for i in range(len(blist)) if blist[i] == k] for k in set(blist)}

The only problem is that the time complexity is O(n^2) in worst case, inadequate for large lists. 唯一的问题是,在最坏的情况下,时间复杂度为O(n ^ 2),对于大型列表而言,这是不够的。

This is the shortest expression I can come up with currently: 这是我目前能想到的最短的表达:

from itertools import groupby

{k: {x[1] for x in v} for k, v in groupby(sorted(zip(blist, alist)), lambda x: x[0])}

The relevant (and not yet mentioned) part is the call to groupby , also described in the following similar question: Python group by 相关的(尚未提及)部分是对groupby的调用,在以下类似的问题中也进行了描述: Python group by

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM