为啥 itertools groupby 不能按预期工作? [复制]

Posted

技术标签:

【中文标题】为啥 itertools groupby 不能按预期工作? [复制]【英文标题】:Why doesn't itertools groupby work as expected? [duplicate]为什么 itertools groupby 不能按预期工作? [复制] 【发布时间】:2018-01-30 17:46:39 【问题描述】:

我正在尝试将整数列表分成奇数组和偶数组。

>>> from itertools import groupby
>>> L = [1,2,3,4]
>>> grouped = [list(g) for k,g in groupby(L, key=lambda x: x % 2)]
>>> grouped
[[1], [2], [3], [4]]

显然,这不是我想要的。但是,如果我首先使用相同的 lambda 键对 L 进行排序,它会按预期工作:

>>> L.sort(key=lambda x: x % 2)
>>> L
[2, 4, 1, 3]
>>> grouped = [list(g) for k,g in groupby(L, key=lambda x: x % 2)]
>>> grouped
[[2, 4], [1, 3]]

我不明白为什么需要预分类。似乎 groupby 应该遍历列表中的整数,根据键函数为每个整数分配一个值,然后对它们进行分组——不管列表顺序如何。

【问题讨论】:

请先阅读documentation,这样您就知道您所使用的功能实际上应该做什么。 在文档中解释得很清楚:docs.python.org/2/library/itertools.html#itertools.groupby “似乎”为什么会出现?你读过文档吗? 您应该首先按该键对可迭代对象进行排序,然后对其进行分组!喜欢:L = sorted(L,key=lambda x:x%2) 知道了。我以前读过文档并认为我理解了,但显然我没有。这里有一个重点:“每次键函数的值发生变化时,它都会生成一个中断或新组(这就是为什么通常需要使用相同的键函数对数据进行排序的原因)。”在发布我的问题之前,我应该重新阅读此内容。对不起。 【参考方案1】:

itertools.groupby 会将满足关键功能的连续项分组。请参阅下面的 (key, group) 对。注意最后相邻偶数项会发生什么:

>>> from itertools import groupby


>>> lst = [1, 2, 3, 4, 6, 8]
>>> grouped = [(k, list(g)) for k, g in groupby(lst, key=lambda x: x % 2)]
>>> grouped
[(1, [1]), (0, [2]), (1, [3]), (0, [4, 6, 8])]

这里有一些获得偶数组和赔率组的方法:

>>> lst = [1, 2, 3, 4]

# OK, post-process groupby iterator
>>> grouped = [(k, list(g)) for k, g in groupby(lst, key=lambda x: x % 2)]
>>> evens = [x[1][0] for x in grouped if not x[0]]
>>> odds = [x[1][0] for x in grouped if x[0]]
>>> evens, odds
([2, 4], [1, 3])

# Better, pre-"sort"/rearrange iterable then groupby (see comments)
>>> key = lambda x: x % 2
>>> rearranged = sorted(lst, key=key)
>>> evens, odds = [(list(g)) for k, g in groupby(rearranged, key=key)]
>>> evens, odds
([2, 4], [1, 3])

# Even Better, simple list comprehensions
>>> evens, odds = [x for x in lst if not x % 2], [x for x in lst if x % 2]
>>> evens, odds
([2, 4], [1, 3])

有关itertools.groupby 的更多信息,请参阅docs 和此post。


替代品

对于复杂的分组,您可以映射一个函数并在 defaultdict 中收集值。

>>> import collections as ct


>>> def even_odd(elem):
...     key = "odd" if elem % 2 else "even"
...     return key, elem

>>> dd = ct.defaultdict(list)
>>> for k, v in map(even_odd, range(1, 5)):
...     dd[k].append(v)  
>>> dd
defaultdict(list, 'even': [2, 4], 'odd': [1, 3])

【讨论】:

【参考方案2】:

知道了。我以前读过文档并认为我理解了,但显然我没有。这是重点:

“每次键函数的值发生变化时,它都会生成一个中断或新组(这就是为什么通常需要使用相同的键函数对数据进行排序)。” [强调我的。]

在发布我的问题之前,我应该重新阅读此内容。对不起。

【讨论】:

以上是关于为啥 itertools groupby 不能按预期工作? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 itertools.groupby 可以将 NaN 分组在列表中而不是 numpy 数组中

python中的itertools.groupby()

显然是用 itertools.groupby 生成的空组

《笔记》python itertools的groupby分组数据处理

itertools.groupby 的反面?

如何使用 itertools 提取 groupby 值?