Cycle a list from alternating sides

后端 未结 15 2108
温柔的废话
温柔的废话 2020-12-14 01:03

Given a list

a = [0,1,2,3,4,5,6,7,8,9]

how can I get

b = [0,9,1,8,2,7,3,6,4,5]

That is, produce a new lis

15条回答
  •  遥遥无期
    2020-12-14 01:49

    The basic principle behind your question is a so-called roundrobin algorithm. The itertools-documentation-page contains a possible implementation of it:

    from itertools import cycle, islice
    
    def roundrobin(*iterables):
        """This function is taken from the python documentation!
        roundrobin('ABC', 'D', 'EF') --> A D E B F C
        Recipe credited to George Sakkis"""
        pending = len(iterables)
        nexts = cycle(iter(it).__next__ for it in iterables) # next instead of __next__ for py2
        while pending:
            try:
                for next in nexts:
                    yield next()
            except StopIteration:
                pending -= 1
                nexts = cycle(islice(nexts, pending))
    

    so all you have to do is split your list into two sublists one starting from the left end and one from the right end:

    import math
    mid = math.ceil(len(a)/2) # Just so that the next line doesn't need to calculate it twice
    
    list(roundrobin(a[:mid], a[:mid-1:-1]))
    # Gives you the desired result: [0, 9, 1, 8, 2, 7, 3, 6, 4, 5]
    

    alternatively you could create a longer list (containing alternating items from sequence going from left to right and the items of the complete sequence going right to left) and only take the relevant elements:

    list(roundrobin(a, reversed(a)))[:len(a)]
    

    or using it as explicit generator with next:

    rr = roundrobin(a, reversed(a))
    [next(rr) for _ in range(len(a))]
    

    or the speedy variant suggested by @Tadhg McDonald-Jensen (thank you!):

    list(islice(roundrobin(a,reversed(a)),len(a)))
    

提交回复
热议问题