如何反转itertools.chain对象?

时间:2011-02-15 20:07:21

标签: python generator itertools

我的功能创建了一系列生成器:

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

我的功能有时需要以相反的顺序返回chained。从概念上讲,我希望能够做到以下几点:

if num < 0:
    return reversed(chained)
return chained

不幸的是:

>>> reversed(chained)
TypeError: argument to reversed() must be a sequence

我有什么选择?

这是一些实时的图形渲染代码,所以我不想让它太复杂/慢。

修改: 当我第一次提出这个问题时,我没有考虑过发电机的可逆性。正如许多人所指出的那样,发电机无法逆转。

我确实想要扭转链条中扁平的内容;不仅仅是发电机的顺序。

基于响应,我没有单一的调用来反转itertools.chain,所以我认为这里唯一的解决方案是使用一个列表,至少在相反的情况下,也许两者都可以。

7 个答案:

答案 0 :(得分:10)

if num < 0:
    lst = list(chained)
    lst.reverse()
    return lst
else:
    return chained

reversed()需要一个实际的序列,因为它通过索引向后迭代它,这对于生成器(它只有“next”项的概念)不起作用。

由于您无论如何都需要展开整个生成器以进行反转,因此最有效的方法是将其读取到列表并使用.reverse()方法就地反转列表。

答案 1 :(得分:9)

您无法按定义反转生成器。生成器的接口是迭代器,它是一个仅支持前向迭代的容器。当你想要反转迭代器时,你必须先收集它的所有项目,然后再反转它们。

改为使用列表或从头开始向后生成序列。

答案 2 :(得分:3)

itertools.chain需要实现__reversed__()(这是最好的)或__len__()__getitem__()

由于它没有,甚至没有办法访问内部序列,您需要扩展整个序列才能反转它。

reversed(list(CHAIN_INSTANCE))

当所有序列都可以反转时,如果链可以使__reversed__()可用,那将是很好的,但目前它不会这样做。也许你可以编写自己的链条版本

答案 3 :(得分:1)

def reversed2(iter):
    return reversed(list(iter))

答案 4 :(得分:0)

reversed仅适用于支持len和索引的对象。在将reversed包裹起来之前,您必须先生成生成器的所有结果。

但是,您可以轻松地执行此操作:

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

答案 5 :(得分:0)

这适用于您的真实应用吗?

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

答案 6 :(得分:0)

理论上你不能因为链式对象甚至可能包含无限序列,例如itertools.count(...)

您应该尝试反转您的生成器/序列,或者对每个序列使用reversed(iterable)(如果适用),然后将它们链接到最后一个。当然,这在很大程度上取决于您的使用案例。