将Python字典键分组为列表,并创建一个以此列表为值的新字典

56

我有一个Python字典

d = {1: 6, 2: 1, 3: 1, 4: 9, 5: 9, 6: 1}

由于上述字典中的值不是唯一的,我想将所有唯一值的键分组为列表,并创建一个新字典,如下所示:

v = {6:[1], 1:[2, 3, 6], 9: [4, 5]}

请注意新字典 v 的键应该被排序。我发现很难将这个字典创建可视化并实现。

2个回答

90

使用 collections.defaultdict 可以更方便地进行操作:

from collections import defaultdict

v = defaultdict(list)

for key, value in sorted(d.items()):
    v[value].append(key)

但你也可以使用普通的 dict,通过使用dict.setdefault()函数来完成:

v = {}

for key, value in sorted(d.items()):
    v.setdefault(value, []).append(key)

以上排序首先按键值排序;后来再对输出字典的值进行排序则更加麻烦和低效。

如果有人不需要输出被排序,可以省略sorted()调用,并使用集合(输入字典中的键值保证唯一,因此不会丢失信息):

v = {}

for key, value in d.items():
    v.setdefault(value, set()).add(key)

制造:

{6: {1}, 1: {2, 3, 6}, 9: {4, 5}}

输出的集合值是有序的纯属巧合,这是整数哈希值实现的副作用;集合是无序结构。


1
如果您选择使用defaultdict,但不希望在初始化字典后继续使用“默认”行为,则可以将default_factory属性设置为None。然后,您的defaultdict将在几乎所有方面上表现得像常规字典。 - mgilson
顺便说一下,我非常喜欢你排序的方式,而不是像大多数人(或者至少是我)最初的直觉那样按值进行排序。+1。 - mgilson
第二行中的“list”是什么?看起来只需使用v = defaultdict()即可工作。 - clwen
1
@clwen:不行,那样做不行。defaultdict()需要一个工厂函数,也就是说,当调用时,它会产生一个新的对象插入到字典中,当键不存在时。传递list意味着每当一个键不存在时,v[value]会导致defaultdict对象调用list()并将结果插入到该键的字典中。如果省略工厂函数,则defaultdict就像普通字典一样,并为缺少的键引发KeyError异常。 - Martijn Pieters
“稍后对输出字典的值进行排序更加麻烦且效率低下。” 我有点龟毛,但是从渐近意义上讲,对分组列表进行排序比先对所有键进行排序要快... - user357269

26

如果最终实际上不需要 dict,则可以使用itertools.groupby

from itertools import groupby
from operator import itemgetter

for k, v in groupby(sorted(d.items(), key=itemgetter(1)), itemgetter(1)):
    print(k, list(map(itemgetter(0), v)))
当然,如果你真的想要,你可以使用这个来构建一个字典:
{
    k: list(map(itemgetter(0), v))
    for k, v in groupby(sorted(d.items(), key=itemgetter(1)), itemgetter(1))
}

但此时,您最好使用Martijn的defaultdict解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接