python groupby的行为?

问题描述 投票:14回答:3
>>from itertools import groupby
>>keyfunc = lambda x : x > 500
>>obj = dict(groupby(range(1000), keyfunc))
>>list(obj[True])
[999]
>>list(obj[False])
[]

范围(x> 500)默认情况下对范围(1000)进行排序。 我期待从0到999的数字按条件(x> 500)分组在dict中。但由此产生的字典只有999。 其他数字在哪里?谁能解释一下这里发生了什么?

python dictionary iterator group-by
3个回答
22
投票

来自docs

返回的组本身是一个迭代器,它与groupby()共享底层迭代。由于源是共享的,因此当groupby()对象前进时,前一组不再可见。因此,如果以后需要该数据,则应将其存储为列表[。]

并且您将在obj中存储迭代器并在以后实现它们。

In [21]: dict((k, list(g)) for k, g in groupby(range(10), lambda x : x > 5))
Out[21]: {False: [0, 1, 2, 3, 4, 5], True: [6, 7, 8, 9]}

9
投票

groupby迭代器返回分组函数结果的元组和一个新的迭代器,它与groupby运算符正在处理的相同“外部”迭代器相关联。当你将dict()应用于由groupby返回的迭代器而不使用这个“内部”迭代器时,groupby将不得不为你推进“外部”迭代器。您必须意识到groupby函数不会对序列起作用,它会将任何此类序列转换为迭代器。

也许用一些比喻和手工操作可以更好地解释这一点。请跟随我们形成一条铲斗线。

想象一下,迭代器是一个人从井中抽水桶的人。他有无限数量的桶可供使用,但井可能是有限的。每当你向这个人要一桶水时,他会从水井中抽出一个新桶并将它传递给你。

groupby案例中,您将另一个人插入到您的萌芽桶链中。这个人根本没有立即通过水桶。每次你要求一个水桶时,他会把你给它的指示结果和另一个人传给你,然后他会通过groupby人向你传递水桶给任何人,只要他们与指示相同的结果。如果指令的结果发生变化,groupby铲斗传球将停止传递这些铲斗。因此,wellgroupby提供了桶,group A将此传递给了一个每组人,group Bgroupby,等等。

在您的示例中,水是编号的,但是从井中只能抽出1000个水桶。以下是当你将dict()人传递给dict()电话时会发生什么:

  1. 你的groupby打电话问groupby一桶。现在,dict()要求井上人员提供一个水桶,记得给出的指示结果,坚持到水桶。对于False,他将通过指令的结果(group A)加上一个新人group A。结果存储为键,并且想要拉桶的dict()人被存储为值。然而,这个人还没有要求桶,因为没有人要求它。
  2. 你的groupby电话要求groupby换另一个桶。 groupby有这些说明,并寻找结果发生变化的下一个桶。它仍然坚持着第一个水桶,没有人要求它,所以它扔掉了这个水桶。相反,它要求井中的下一个桶并使用他的指令。结果和以前一样,所以它也抛弃了这个新桶!更多的水流过地板,所以下一个499桶。只有当数量为501的桶通过才会改变结果,所以现在group B找到另一个人给(人True)指示,连同新结果dict(),将这两个传递给dict()
  3. 你的True电话存储group B作为关键,人group B作为价值。 dict()什么都不做,没有人要求它换水。
  4. 你的groupby要求另一个桶。 groupby溢出更多的水,直到它拿着数量为999的水桶,井里的人耸了耸肩,说现在井已空了。 dict()告诉dict()这个井是空的,没有更多的水桶即将来临,他可以随便停止询问。它仍然保持数量为999的铲斗,因为它永远不必为井中的下一个铲斗腾出空间。
  5. 现在你来,问True与关键group B相关的事情,这是人group B。你将list()传递给group B,因此将向group B询问group B可以得到的所有桶。 groupby回到group B,他只拥有一个水桶,数量为999的水桶,这个水桶的指示结果与group B正在寻找的相符。所以这一桶list()给了groupby,然后耸了耸肩,因为没有更多的桶,因为dict()告诉他。
  6. 然后你问False与关键group A相关联的人,即人groupby。到目前为止,list()已经没有任何东西可以提供了,井是干燥的,他站在一滩999桶水中,数字漂浮在周围。你的第二个groupby什么都没得到。

这个故事的寓意?在与>>> from itertools import groupby >>> keyfunc = lambda x : x > 5 >>> obj = dict((k, list(v)) for k, v in groupby(range(10), keyfunc)) >>> obj(True) [0, 1, 2, 3, 4, 5] >>> obj(False) [6, 7, 8, 9] 交谈时,立即要求所有水桶,因为如果你不这样做,他会把所有水都洒掉!迭代器就像幻想曲中的扫帚,在没有理解的情况下勤奋地移动水,如果你不知道如何控制它们,你最好希望你用完水。

这里的代码可以达到您的预期(使用少量水来防止泛滥):

range(1000)

4
投票

你缺少的是,groupby函数迭代你给定的999,从而返回1000个值。你只保存最后一个,在你的情况下dictionary = {} keyfunc = lambda x : x > 500 for k, g in groupby(range(1000), keyfunc): dictionary[k] = list(g) 。你要做的是迭代返回值并将它们保存到你的字典中:

{False: [0, 1, 2, ...], True: [501, 502, 503, ...]}

所以你会得到预期的输出:

itertools groupby

有关更多信息,请参阅有关qazxswpoi的Python文档。

© www.soinside.com 2019 - 2024. All rights reserved.