Python 如何反转itertools.chain对象?
My函数创建一个生成器链:Python 如何反转itertools.chain对象?,python,generator,itertools,Python,Generator,Itertools,My函数创建一个生成器链: def bar(num): import itertools some_sequence = (x*1.5 for x in range(num)) some_other_sequence = (x*2.6 for x in range(num)) chained = itertools.chain(some_sequence, some_other_sequence) return chained 我的函数有时需要以相反的顺
def bar(num):
import itertools
some_sequence = (x*1.5 for x in range(num))
some_other_sequence = (x*2.6 for x in range(num))
chained = itertools.chain(some_sequence, some_other_sequence)
return chained
我的函数有时需要以相反的顺序返回链接的。从概念上讲,我希望能够做到以下几点:
if num < 0:
return reversed(chained)
return chained
我有什么选择
这是一些实时图形渲染代码,所以我不想让它太复杂/太慢
编辑:
当我第一次提出这个问题时,我没有考虑发电机的可逆性。正如许多人指出的那样,发电机是不能反转的
事实上,我确实想扭转链条中扁平的内容;不仅仅是发电机的顺序
根据响应,我无法使用单个调用来反转itertools.chain,因此我认为这里唯一的解决方案是使用列表,至少对于反转的情况,或者两者都使用。reversed
仅适用于支持len
和索引的对象。您必须先生成生成器的所有结果,然后再将其包装起来
但是,您可以轻松做到这一点:
def bar(num):
import itertools
some_sequence = (x*1.5 for x in range(num, -1, -1))
some_other_sequence = (x*2.6 for x in range(num, -1, -1))
chained = itertools.chain(some_other_sequence, some_sequence)
return chained
这在你的真实应用程序中有效吗
def bar(num):
import itertools
some_sequence = (x*1.5 for x in range(num))
some_other_sequence = (x*2.6 for x in range(num))
list_of_chains = [some_sequence, some_other_sequence]
if num < 0:
list_of_chains.reverse()
chained = itertools.chain(*list_of_chains)
return chained
def条(num):
进口itertools
某些_序列=(x*1.5表示范围内的x(num))
some_other_sequence=(x*2.6表示范围内的x(num))
_链列表=[某些_序列,某些_其他_序列]
如果num<0:
列出\u链的\u。反向()
chained=itertools.chain(*链列表)
返回链
如果num<0:
lst=列表(链接)
倒转
返回lst
其他:
返回链
reversed()
需要一个实际的序列,因为它通过索引向后迭代,而这对于生成器(它只有“下一个”项的概念)是不起作用的
由于您无论如何都需要展开整个生成器以进行反转,因此最有效的方法是将其读取到列表中,然后使用.reverse()
方法原地反转列表。您无法根据定义反转生成器。生成器的接口是迭代器,迭代器是只支持正向迭代的容器。当您想要反转迭代器时,必须首先收集迭代器的所有项,然后再反转它们
改为使用列表或从一开始就向后生成序列。理论上不能,因为链接对象甚至可能包含无限序列,例如itertools.count(…)
您应该尝试反转生成器/序列,或者对每个序列使用reversed(iterable)
,如果适用,然后将它们从上到下链接在一起。当然,这在很大程度上取决于您的用例。itertools.chain需要实现\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu()(这将是最好的)或\uuuuuuuuuuuuuuuuuuuuuuuu
因为没有,甚至没有办法访问内部序列,所以需要扩展整个序列才能反转它
reversed(list(CHAIN_INSTANCE))
如果chain在所有序列都是可反转的情况下使\uuuuu reversed\uuuuuuu()
可用,那就太好了,但目前它没有做到这一点。也许你可以编写自己版本的chain,它可以Hm,我本以为itertools.islice
加上一个负的步骤就可以了,但事实证明只有正值才对arg到islice
有效。有趣的问题。不仅仅是链接的,还有你的生成器:>>反向((范围(5)中的x代表x))
TypeError:argument to reversed()必须是一个序列
@jleedev良好点;即使有办法反转itertools.chain,也无法反转生成器。我以前没有意识到这一点,但现在明白了。但是,reversed在完全由列表组成的itertools.chain上也不起作用。是的,但是如果您需要访问一般情况下的最后一项(这意味着reversed),则必须耗尽生成器。如果看不到真正的代码,就不可能提供更好的解决方案。@Ant shang、Jochen Ritzel和其他人都提到过,发电机不能在不耗尽它们的情况下反转。当我提出最初的问题时,我没有考虑到这一点。至少shang的解决方案只在num<0的条件下展开生成器。这会反转链中序列的顺序,而不是序列本身<代码>L1=[1,2,3];L2=[4,5,6]
将这两个链接起来,并反转结果,它是[6,5,4,3,2,1]
,使用您的解决方案,它将是[4,5,6,1,2,3]
,不是吗?我认为这是op的意思。没有办法在不耗尽它的情况下反转生成器返回的值的顺序…感谢您的建议。当我提出最初的问题时,我没有考虑到生成器不能反转,所以事实上我想反转链中扁平的内容,而不是链本身中生成器的顺序。实现\uuuuuuu reversed\uuuuu
的对象也将使用reversed()
:
def reversed2(iter):
return reversed(list(iter))
reversed(list(CHAIN_INSTANCE))
def reversed2(iter):
return reversed(list(iter))