对于条件(x> 500),>>from itertools import groupby >>keyfunc = lambda x : x > 500 >>obj = dict(groupby(range(1000), keyfunc)) >>list(obj[True]) [999] >>list(obj[False]) []
范围(1000)显然是默认排序的。
我期望条件(x> 500)将0到999之间的数字分组在 dict 中。但由此产生的字典只有999。
其他数字在哪里?
任何人都可以解释这里发生了什么吗?
答案 0 :(得分:22)
来自docs:
返回的组本身就是一个迭代器,它与
groupby()
共享底层的iterable。由于源是共享的,因此当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]}
答案 1 :(得分:9)
groupby
迭代器返回分组函数结果的元组和一个新的迭代器,它与groupby
运算符正在处理的同一个“外部”迭代器相关联。当您将dict()
应用于groupby
返回的迭代器而不使用此“内部”迭代器时,groupby
将必须为您推进“外部”迭代器。您必须意识到groupby
函数不会对序列起作用,它会将任何此类序列转换为迭代器。
也许用一些比喻和手工操作可以更好地解释这一点。请跟随我们形成一条铲斗线。
想象一下,迭代器是一个人从井中抽水桶的人。他有无限数量的桶可供使用,但井可能是有限的。每当你向这个人要一桶水时,他都会从水井中抽出一个新桶并传递给你。
在groupby
案例中,您将另一个人插入到您的新手链中。这个人根本没有立即通过水桶。每次你要求一个水桶时,他都会通过你给你的指示结果加上另一个的人,然后他会通过groupby
人向你传递水桶给任何人,只要它们与指令的结果相同。如果指令的结果发生变化,groupby
存储桶传递将停止传递这些存储桶。因此,well
会向groupby
提供存档,并将其传递给每个群组的人group A
,group B
,等等。
在您的示例中,水被编号,但是从井中只能抽出1000个水桶。当您将groupby
人传递给dict()
来电时,会发生以下情况:
您的dict()
电话会向groupby
询问存储桶。现在,groupby
要求井中人员提供一个水桶,记住所给出的指示的结果,并坚持到水桶。要dict()
,他会传递说明的结果(False
)加上新人group A
。结果存储为密钥,并且想要提取存储桶的group A
人员存储为值。然而,这个人不还要求存储桶,因为没有人要求它。
您的dict()
来电询问groupby
另一个存储桶。 groupby
有这些说明,并寻找结果发生变化的下一个桶。它仍然坚持第一个桶,没有人要求它,所以扔掉这个桶。相反,它要求井中的下一个桶并使用他的指令。结果和以前一样,所以它也抛弃了这个新桶!更多的水流过地板,所以下一个499桶。只有当数量为501的存储桶被传递时,结果才会发生变化,所以现在groupby
找到另一个人(新人group B
)和新结果True
发送指令,传递这两个到dict()
。
您的dict()
来电存储True
作为密钥,人group B
作为值。 group B
什么也没做,没有人要求它换水。
您的dict()
要求另一个存储桶。 groupby
溢出更多的水,直到它拥有数字为999的桶,并且井中的人耸了耸肩并说明现在井是空的。 groupby
告诉dict()
这个井是空的,不再有水桶来了,请他不要再问了。它仍然保持数量为999的水桶,因为它永远不必为井中的下一个水桶腾出空间。
现在你来了,向dict()
询问与密钥True
相关联的内容,即group B
人。您将group B
传递给list()
,因此会向group B
询问所有存储桶group B
可以获得的内容。 group B
返回groupby
,只持有一个存储桶,数量为999的存储桶,此存储桶的指令结果与group B
正在查找的内容相匹配。所以这一桶group B
给了list()
,然后耸了耸肩,因为没有更多的桶,因为groupby
告诉了他。
然后,您向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]
答案 2 :(得分:4)
你缺少的是,groupby-function迭代你给定的range(1000)
,从而返回1000个值。在您的案例999
中,您只保存最后一个。你要做的是迭代返回值并将它们保存到你的字典中:
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。
的Python文档