为什么只用 itemgetter 和 groupby 返回最后一个条目

why only the last entry is returned with itemgetter and groupby

我想知道下面的代码 returns 是否符合预期?

我 运行 在 Python 3.7.

我期待 "Expected" 输出,但只返回每个组的最后一个条目,如 "Actual" 所示。

import operator
import itertools

adict = {'a': 1, 'b':3, 'c': 1, 'd': 2, 'e': 3, 'f': 1}

dict((i, dict(v)) for i, v in itertools.groupby(adict.items(), operator.itemgetter(1))) 
Expected Output: {1: {'a': 1, 'c': 1, 'f':1}, 2: {'d': 2}, 3: {'b', 'e'} }

Actual : {1: {'f': 1}, 3: {'e': 3}, 2: {'d': 2}}

如果你分解 dict((i, dict(v)) for i, v in itertools.groupby(adict.items(), operator.itemgetter(1))) 应该清楚为什么只有最后一个键值对在最后的字典中:

for i, v in itertools.groupby(adict.items(), operator.itemgetter(1)):
    print(i, dict(v))

产出

1 {'a': 1}
3 {'b': 3}
1 {'c': 1}
2 {'d': 2}
3 {'e': 3}
1 {'f': 1}

对其中​​的每一个调用 dict 将使用相同的外键覆盖先前创建的字典。

可以通过使用 defaultdict(dict) 来修复它,同时确保 update 现有的内部字典具有新的键值对:

from collections import defaultdict

adict = {'a': 1, 'b': 3, 'c': 1, 'd': 2, 'e': 3, 'f': 1}

output = defaultdict(dict)
for i, v in adict.items():
    output[v][i] = v
print(output)

产出

defaultdict(<class 'dict'>, {1: {'a': 1, 'c': 1, 'f': 1}, 3: {'b': 3, 'e': 3}, 2: {'d': 2}})

您不必使用 defaultdict,但它节省了存在性检查:

adict = {'a': 1, 'b': 3, 'c': 1, 'd': 2, 'e': 3, 'f': 1}

output = {}
for i, v in adict.items():
    if v in output:
        output[v][i] = v
    else:
        output[v] = {i: v}
print(output)

产出

{1: {'a': 1, 'c': 1, 'f': 1}, 3: {'b': 3, 'e': 3}, 2: {'d': 2}}


正如 Jon 在评论中提到的,这也可以通过先按相同的键 (operator.itemgetter(1)) 对 adict.values 进行排序来解决:

dict((i, dict(v)) for i, v in itertools.groupby(sorted(adict.items(), key=itemgetter(1)), operator.itemgetter(1)))

此警告实际上在 itertools.groupby documentation:

中提到

... Generally, the iterable needs to already be sorted on the same key function.