为啥 itertools.groupby() 不起作用? [复制]

Posted

技术标签:

【中文标题】为啥 itertools.groupby() 不起作用? [复制]【英文标题】:Why itertools.groupby() doesn't work? [duplicate]为什么 itertools.groupby() 不起作用? [复制] 【发布时间】:2018-05-06 10:21:25 【问题描述】:

我检查了一些关于 groupby() 的主题,但我不明白我的示例有什么问题:

students = ['name': 'Paul',    'mail': '@gmail.com',
            'name': 'Tom',     'mail': '@yahoo.com',
            'name': 'Jim',     'mail': 'gmail.com',
            'name': 'Jules',   'mail': '@something.com',
            'name': 'Gregory', 'mail': '@gmail.com',
            'name': 'Kathrin', 'mail': '@something.com']

key_func = lambda student: student['mail']

for key, group in itertools.groupby(students, key=key_func):
    print(key)
    print(list(group))

这会分别打印每个学生。为什么我没有只得到 3 个组:@gmail.com@yahoo.com@something.com

【问题讨论】:

Jim 的电子邮件是 gmail.com,而不是像其他人一样的 @gmail.com。错字? 【参考方案1】:

首先,有些邮件是gmail.com,有些是@gmail.com,这就是为什么它们被视为单独的组。

groupby 还期望数据由相同的key 函数预先排序,这解释了为什么您会得到两次@something.com

来自docs:

... 通常,iterable 需要已经在相同的 key 函数上排序。 ...

students = ['name': 'Paul', 'mail': '@gmail.com', 'name': 'Tom', 'mail': '@yahoo.com',
            'name': 'Jim', 'mail': 'gmail.com', 'name': 'Jules', 'mail': '@something.com',
            'name': 'Gregory', 'mail': '@gmail.com', 'name': 'Kathrin', 'mail': '@something.com']

key_func = lambda student: student['mail']

students.sort(key=key_func)
# sorting by same key function we later use with groupby

for key, group in itertools.groupby(students, key=key_func):
    print(key)
    print(list(group))

#  @gmail.com
#  ['name': 'Paul', 'mail': '@gmail.com', 'name': 'Gregory', 'mail': '@gmail.com']
#  @something.com
#  ['name': 'Jules', 'mail': '@something.com', 'name': 'Kathrin', 'mail': '@something.com']
#  @yahoo.com
#  ['name': 'Tom', 'mail': '@yahoo.com']
#  gmail.com
#  ['name': 'Jim', 'mail': 'gmail.com']

在修复排序和gmail.com/@gmail.com 之后,我们得到了预期的输出:

import itertools

students = ['name': 'Paul', 'mail': '@gmail.com', 'name': 'Tom', 'mail': '@yahoo.com',
            'name': 'Jim', 'mail': '@gmail.com', 'name': 'Jules', 'mail': '@something.com',
            'name': 'Gregory', 'mail': '@gmail.com', 'name': 'Kathrin', 'mail': '@something.com']

key_func = lambda student: student['mail']

students.sort(key=key_func)

for key, group in itertools.groupby(students, key=key_func):
    print(key)
    print(list(group))

#  @gmail.com
#  ['mail': '@gmail.com', 'name': 'Paul',
#   'mail': '@gmail.com', 'name': 'Jim',
#   'mail': '@gmail.com', 'name': 'Gregory']
#  @something.com
#  ['mail': '@something.com', 'name': 'Jules',
#   'mail': '@something.com', 'name': 'Kathrin']
#  @yahoo.com
#  ['mail': '@yahoo.com', 'name': 'Tom']

【讨论】:

好的,我已经阅读了文档,并且看到必须对序列进行排序,但由于无法对字典进行排序,我迷路了。我创建了一个混乱的代码。 @kviatek 这是关于对字典的列表进行排序,而不是字典本身。 我正在尝试将问题编辑为更合适的重复目标;如果我像其他人一样将 Jim 的电子邮件从 gmail.com 更改为 @gmail.com,您介意吗?这与我认为的问题无关。 @Aran_Fey 是的,当然,我已经看到你已经这样做了,但无论如何我都会回应。 DeepSpace 是的,我知道,但就像我说过的那样,我迷失在所有对象中,最后我试图对字典进行排序,显然,这不是必须要做的。现在一切都清楚了。【参考方案2】:

itertools 使用数据的排序顺序。您的列表未排序。

因此,如果您有 ["gmail.com", "something.com", "gmail.com"],itertools 将创建三个组。这与某些函数式语言中的 groupby 不同(或者 Python pandas)。

您需要先对字典进行排序。

import itertools

students = ['name': 'Paul', 'mail': '@gmail.com', 'name': 'Tom',    'mail': '@yahoo.com',
            'name': 'Jim', 'mail': 'gmail.com', 'name': 'Jules', 'mail': '@something.com',
            'name': 'Gregory', 'mail': '@gmail.com', 'name': 'Kathrin', 'mail': '@something.com']


 for key, group in itertools.groupby(sorted(students, key=lambda x: x["mail"]), key=lambda student: student['mail']):
     print(key)
     print(list(group))

# @gmail.com
# ['name': 'Paul', 'mail': '@gmail.com', 'name': 'Gregory', 'mail': '@gmail.com']
# @something.com
# ['name': 'Jules', 'mail': '@something.com', 'name': 'Kathrin', 'mail': '@something.com']
# @yahoo.com
#['name': 'Tom', 'mail': '@yahoo.com']
#gmail.com
# ['name': 'Jim', 'mail': 'gmail.com']

【讨论】:

我不是反对者,但是:这与字典不可排序的事实无关,OP 是按字典的 list 分组的。您可以在我的回答中看到为什么它不能按预期工作 谢谢 DeepSpace。固定。

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

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

python中的itertools.groupby()

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

itertools.groupby 的反面?

由 itertools.groupby() 生成的迭代器被意外消耗

使 Pandas groupby 的行为类似于 itertools groupby