我试图将整数列表分成奇数和偶数组。
>>> 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应该遍历列表中的整数,根据键函数为每个值赋值,然后对它们进行分组 - 无论列表顺序如何。
答案 0 :(得分:2)
itertools.groupby
会将符合关键功能的连续项目分组。请参阅下面的(键,组)对。请注意最后相邻的偶数项会发生什么:
>>> 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]})
答案 1 :(得分:1)
知道了。我以前读过文档并认为我理解,但显然我没有。这是重点:
“每次键函数的值发生变化时,它都会生成一个中断或新组(这就是为什么通常需要使用相同的键函数对数据进行排序的原因)。” [强调我的。]
在发布我的问题之前,我应该重新阅读这篇文章。遗憾。