python groupby的行为?

nat*_*han 14 python dictionary iterator group-by

>>from itertools import groupby
>>keyfunc = lambda x : x > 500
>>obj = dict(groupby(range(1000), keyfunc))
>>list(obj[True])
[999]
>>list(obj[False])
[]
Run Code Online (Sandbox Code Playgroud)

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

wRA*_*RAR 22

来自文档:

返回的组本身是一个迭代器,它与底层的iterable共享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]}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ers 10

groupby迭代器返回的分组功能的结果,被连接到相同的"外部"一个新的迭代的迭代器的元组的groupby运营商正在努力.当你dict()groupby不使用这个"内部"迭代器的情况下应用于返回的迭代器时,groupby必须为你推进"外部"迭代器.你必须意识到groupby函数不会对序列起作用,它会将任何这样的序列转换为迭代器.

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

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

在这种groupby情况下,您将另一个人插入到您的萌芽桶链中.这个人根本没有立即通过水桶.每次你要求一个水桶时,他会把你给它的指示结果和另一个人传递给你,然后他会通过这个groupby人向你传递水桶给任何人,只要他们与指示相同的结果.该groupby桶过路人将停止通过这些桶,如果指令的结果改变.所以well给人的水桶groupby,这谁传递给每个组的人,group A,group B,等等.

在您的示例中,水是编号的,但是从井中只能抽出1000个水桶.以下是当您将此groupby人传递给dict()电话时发生的情况:

  1. 你的dict()电话要求groupby一个水桶.现在,groupby要求井中人员提供一个水桶,记住给出的指示结果,抓住水桶.为了dict()他会通过的指示(结果False),加上一个新的人,group A.结果存储为密钥,并且group A想要提取桶的人被存储为值.然而,这个人还没有要求桶,因为没有人要求它.

  2. 你的dict()电话要求groupby另一个桶.groupby有这些说明,并寻找结果变化的下一个桶.它仍然坚持着第一个水桶,没有人要求它,所以它扔掉了这个水桶.相反,它要求井中的下一个桶并使用他的指令.结果和以前一样,所以它也抛弃了这个新桶!更多的水流过地板,所以下一个499桶.只有当数量为501的存储桶被传递时,结果才会改变,所以现在groupby找到另一个人给(人group B)指示,连同新结果,True将这两个传递给dict().

  3. 您的dict()呼叫存储True为密钥,而人员group B作为值.group B什么都不做,没有人要求它换水.

  4. dict()问另一个桶.groupby溢出更多的水,直到它拿着数量为999的桶,井里的人耸了耸肩,说现在井已空了.groupby告诉dict()井是空的,没有更多的桶来,他可以请你停止询问.它仍然保持数量为999的铲斗,因为它永远不必为井中的下一个铲斗腾出空间.

  5. 现在你来了,要求dict()与钥匙相关的东西True,即人group B.您传递group Blist(),因此这将要求group B所有的桶group B可以得到的.group B回到groupby,谁只拥有一个桶,数量为999的桶,并且该桶的指令的结果与所group B寻找的匹配.所以这一个桶group B给了list(),然后耸了耸肩,因为没有更多的桶,因为groupby告诉他.

  6. 然后dict(),您要求与该密钥相关联的人False,即人group A.到现在为止,groupby没有什么可以再给的,井是干的,他站在一滩999桶水中,数字漂浮在周围.你的第二个list()什么都没有

这个故事的寓意?在交谈时立即要求所有水桶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]
Run Code Online (Sandbox Code Playgroud)