How do I reverse an itertools.chain object?

后端 未结 7 1062
佛祖请我去吃肉
佛祖请我去吃肉 2021-02-14 16:01

My function creates a chain of generators:

def bar(num):
    import itertools
    some_sequence = (x*1.5 for x in range(num))
    some_other_sequence = (x*2.6 fo         


        
相关标签:
7条回答
  • 2021-02-14 16:14

    itertools.chain would need to implement __reversed__() (this would be best) or __len__() and __getitem__()

    Since it doesn't, and there's not even a way to access the internal sequences you'll need to expand the entire sequence to be able to reverse it.

    reversed(list(CHAIN_INSTANCE))
    

    It would be nice if chain would make __reversed__() available when all the sequences are reversable, but currently it does not do that. Perhaps you can write your own version of chain that does

    0 讨论(0)
  • 2021-02-14 16:17

    reversed only works on objects that support len and indexing. You have to first generate all results of a generator before wrapping reversed around them.

    However, you could easily do this:

    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
    
    0 讨论(0)
  • 2021-02-14 16:19

    In theory you can't because chained objects may even contain infinite sequences such as itertools.count(...).

    You should try to reverse your generators/sequences or use reversed(iterable) for each sequence if applicable and then chain them together last-to-first. Of course this highly depends on your use case.

    0 讨论(0)
  • 2021-02-14 16:22
    def reversed2(iter):
        return reversed(list(iter))
    
    0 讨论(0)
  • 2021-02-14 16:24

    Does this work in you real app?

    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
    
    0 讨论(0)
  • 2021-02-14 16:25
    if num < 0:
        lst = list(chained)
        lst.reverse()
        return lst
    else:
        return chained
    

    reversed() needs an actual sequence, because it iterates it backwards by index, and that wouldn't work for a generator (which only has the notion of "next" item).

    Since you will need to unroll the whole generator anyway for reversing, the most efficient way is to read it to a list and reverse the list in-place with the .reverse() method.

    0 讨论(0)
提交回复
热议问题