关于python:为字典中的一个键附加多个值

append multiple values for one key in a dictionary

本问题已经有最佳答案,请猛点这里访问。

我刚接触过python,每年都有一个年和值的列表。我要做的是检查年份是否已经存在于字典中,如果存在,则将该值附加到特定键的值列表中。

例如,我有一个年份列表,每年都有一个值:

1
2
3
4
5
6
7
8
2010  
2  
2009  
4  
1989  
8  
2009  
7

我要做的是用年份作为键,用这些数字作为值填充字典。但是,如果我在2009年列出了两次,我希望将第二个值附加到字典中的值列表中,因此我希望:

1
2
3
2010: 2  
2009: 4, 7  
1989: 8

现在我有以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
d = dict()  
years = []  

(get 2 column list of years and values)

for line in list:    
    year = line[0]  
    value = line[1]  

for line in list:  
    if year in d.keys():  
        d[value].append(value)  
    else:  
        d[value] = value  
        d[year] = year


如果我能重新表述你的问题,你想要的是一本字典,上面的年份是键,每一年都有一个数组,其中包含与该年相关的值列表,对吗?我可以这样做:

1
2
3
4
5
6
7
8
9
years_dict = dict()

for line in list:
    if line[0] in years_dict:
        # append the new number to the existing array at this slot
        years_dict[line[0]].append(line[1])
    else:
        # create a new array in this slot
        years_dict[line[0]] = [line[1]]

几年后,你应该得到的是一本如下所示的字典:

1
2
3
4
5
{
   "2010": [2],
   "2009": [4,7],
   "1989": [8]
}

一般来说,创建"并行数组"是一种糟糕的编程实践,在这种情况下,通过具有相同的索引,而不是作为包含这两个数组的容器的适当子级,可以隐式地将各个项关联起来。


最好使用collections.defaultdict(在python 2.5中添加)。这允许您指定缺少键的默认对象类型(如list)。

因此,如果一个键不存在,就不创建它,而是先将它附加到该键的值上,而是删除中间人,直接附加到不存在的键上,以获得所需的结果。

使用数据的快速示例:

1
2
3
4
5
6
7
8
9
10
>>> from collections import defaultdict
>>> data = [(2010, 2), (2009, 4), (1989, 8), (2009, 7)]
>>> d = defaultdict(list)
>>> d
defaultdict(<type 'list'>, {})
>>> for year, month in data:
...     d[year].append(month)
...
>>> d
defaultdict(<type 'list'>, {2009: [4, 7], 2010: [2], 1989: [8]})

这样你就不用担心你是否看到过与一年相关的数字。您只需追加并忘记,知道丢失的键总是一个列表。如果一个键已经存在,那么它将被附加到。


您可以使用setdefault

1
2
for line in list:  
    d.setdefault(year, []).append(value)

这是因为setdefault返回列表并在字典上设置它,并且由于列表是可变的,所以附加到setdefault返回的版本与附加到字典本身的版本相同。如果这有任何意义的话。


1
2
3
4
5
6
7
8
9
d = {}

# import list of year,value pairs

for year,value in mylist:
    try:
        d[year].append(value)
    except KeyError:
        d[year] = [value]

Python之道-接受宽恕比请求许可更容易!


下面是使用not in运算符执行此操作的另一种方法:

1
2
3
4
5
6
7
8
9
10
11
# define an empty dict
years_dict = dict()

for line in list:
    # here define what key is, for example,
    key = line[0]
    # check if key is already present in dict
    if key not in years_dict:
        years_dict[key] = []
    # append some value
    years_dict[key].append(some.value)

如果将这些值放入元组列表中,就更容易了。为此,可以使用列表切片和zip函数。

1
2
data_in = [2010,2,2009,4,1989,8,2009,7]
data_pairs = zip(data_in[::2],data_in[1::2])

zip接受任意数量的列表,在本例中是data_in的偶数和奇数条目,并将它们组合成一个元组。

现在我们可以使用setdefault方法。

1
2
3
data_dict = {}
for x in data_pairs:
    data_dict.setdefault(x[0],[]).append(x[1])

setdefault接受一个键和一个默认值,并返回相关的值,或者如果没有当前值,则返回默认值。在这种情况下,我们将得到一个空的或填充的列表,然后将当前值附加到该列表中。


如果您想要(几乎)一个内衬:

1
2
3
4
from collections import deque

d = {}
deque((d.setdefault(year, []).append(value) for year, value in source_of_data), maxlen=0)

使用dict.setdefault,您可以将"检查密钥是否已存在,如果不存在则生成新列表"的思想封装到单个调用中。这允许您编写一个生成器表达式,该表达式由deque尽可能高效地使用,因为队列长度设置为零。德克将立即丢弃,结果将在d中。

这是我为好玩而做的事。我不建议使用它。有一个时间和地点可以通过一个deque来消费任意的iterables,而这绝对不是。