【问题标题】:why only the last entry is returned with itemgetter and groupby为什么只有最后一个条目与 itemgetter 和 groupby 一起返回
【发布时间】:2019-09-02 14:31:05
【问题描述】:

我想知道下面的代码返回的内容是否符合预期?

我在 Python 3.7 上运行它。

我期望“预期”输出,但只返回每个组的最后一个条目,如“实际”中所示。

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

【问题讨论】:

  • 您的预期输出不一致
  • 无论如何,为什么要嵌套字典?为什么不使用defultdict 可以轻松获得的{1: ['a', 'c', 'f'], 2: ['d'], 3: ['b', 'e']}
  • 嗨@DeepSpace ,我刚刚熟悉了itertools 和运算符函数,并且正在浏览示例,因此遇到了这个问题。这是链接riptutorial.com/python/example/923/operator-module
  • itertools.group 适用于 consecutive 键...其中,您没有任何...并且由于字典具有唯一键,而您正在构建如果您正在用该键的最后一次看到的值替换该组的键...

标签: python python-3.x operator-keyword itertools


【解决方案1】:

如果你打破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 将用相同的外键覆盖之前创建的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 在 cmets 中提到的,这也可以通过首先按相同键 (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.groupbydocumentation中实际上提到了这个警告:

... 一般情况下,iterable 需要已经在同一个 key 函数上排序。

【讨论】:

  • 或者如果一个真的想使用itertools.groupby,那么首先按分组键排序,这样它们都是连续的,例如:dict((i, dict(v)) for i, v in itertools.groupby(sorted(adict.items(), key=itemgetter(1)), operator.itemgetter(1)))
  • @JonClements 正确,这个警告甚至在文档中(序列应该按传递给 groupby 的相同键函数排序)。我加一下
  • 如果您使用的是defaultdict... 只需擦洗整个itertools 的东西,只需使用for i, v in adict.items(): output[v][i] = v...
  • @JonClements 同意
  • 如果你不建议使用defaultdict,那么setdefault是你的朋友,你可以通过使用for i, v in adict.items(): output.setdefault(v, {}).update(((i, v),))来避免存在性检查
猜你喜欢
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-20
相关资源
最近更新 更多