从交替的边循环列表

Pyt*_*nic 27 python iteration algorithm list

给出一个清单

a = [0,1,2,3,4,5,6,7,8,9]
Run Code Online (Sandbox Code Playgroud)

我怎样才能得到

b = [0,9,1,8,2,7,3,6,4,5]
Run Code Online (Sandbox Code Playgroud)

也就是说,产生一个新的列表,其中每个连续的元素交替地从原始列表的两边取出?

Nor*_*man 50

>>> [a[-i//2] if i % 2 else a[i//2] for i in range(len(a))]
[0, 9, 1, 8, 2, 7, 3, 6, 4, 5]
Run Code Online (Sandbox Code Playgroud)

说明:
此代码从一开始就挑选号码(a[i//2])和结束(a[-i//2]的)a,交替(if i%2 else).选择了总数len(a),因此即使len(a)是奇数,也不会产生任何不良影响.
[-i//2 for i in range(len(a))]产率0, -1, -1, -2, -2, -3, -3, -4, -4, -5,
[ i//2 for i in range(len(a))]产量0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
i%2之间交替FalseTrue,
所以我们从提取的索引a是:0, -1, 1, -2, 2, -3, 3, -4, 4, -5.

我对pythonicness的评估:
这个单线程的好处是它很短并且显示出对称性(+i//2-i//2).
但不好的是,这种对称性具有欺骗性:
人们可能会认为这与翻转的标志-i//2相同i//2.但是在Python中,整数除法返回结果的底限而不是截断为零.所以-1//2 == -1.
此外,我发现通过索引访问列表元素比pythonic更少迭代.

  • 这也是少数几个没有遇到奇数列表问题的答案之一.做得好! (2认同)

Tad*_*sen 27

cycle从前锋iterreversed一个获得物品之间.只要确保你停下len(a)islice.

from itertools import islice, cycle

iters = cycle((iter(a), reversed(a)))
b = [next(it) for it in islice(iters, len(a))]

>>> b
[0, 9, 1, 8, 2, 7, 3, 6, 4, 5]
Run Code Online (Sandbox Code Playgroud)

这很容易放在一行,但后来变得更难阅读:

[next(it) for it in islice(cycle((iter(a),reversed(a))),len(a))]
Run Code Online (Sandbox Code Playgroud)

将它放在一行也会阻止你使用另一半迭代器,如果你想:

>>> iters = cycle((iter(a), reversed(a)))
>>> [next(it) for it in islice(iters, len(a))]
[0, 9, 1, 8, 2, 7, 3, 6, 4, 5]
>>> [next(it) for it in islice(iters, len(a))]
[5, 4, 6, 3, 7, 2, 8, 1, 9, 0]
Run Code Online (Sandbox Code Playgroud)


Aks*_*jan 8

Python 2.7中非常好的单行程序:

results = list(sum(zip(a, reversed(a))[:len(a)/2], ()))
>>>> [0, 9, 1, 8, 2, 7, 3, 6, 4, 5]
Run Code Online (Sandbox Code Playgroud)

首先用反向压缩列表,取一半列表,将元组加起来形成一个元组,然后转换为列表.

在Python 3,zip返回一个生成器,所以你必须使用isliceitertools:

from itertools import islice
results = list(sum(islice(zip(a, reversed(a)),0,int(len(a)/2)),()))
Run Code Online (Sandbox Code Playgroud)

编辑:看来这只是完全适用于偶数列表的长度-奇列表的长度将省略中间元素:(一小修正int(len(a)/2)int(len(a)/2) + 1会给你一个重复的中间值,因此被警告.


Zac*_*tes 6

你可以pop来回:

b = [a.pop(-1 if i%2 else 0) for i in range(len(a))]
Run Code Online (Sandbox Code Playgroud)

注意:这会破坏原始列表a.


skr*_*krx 6

使用正确的工具.

from toolz import interleave, take

b = list(take(len(a), interleave((a, reversed(a)))))
Run Code Online (Sandbox Code Playgroud)

首先,我尝试了类似于Raymond Hettinger的迭代工具(Python 3)的解决方案.

from itertools import chain, islice

interleaved = chain.from_iterable(zip(a, reversed(a)))
b = list(islice(interleaved, len(a)))
Run Code Online (Sandbox Code Playgroud)


che*_*ner 5

与其他一些答案没有太大的不同,但它避免了用于确定索引符号的条件表达式.

a = range(10)
b = [a[i // (2*(-1)**(i&1))] for i in a]
Run Code Online (Sandbox Code Playgroud)

i & 1在0和1之间交替.这使得指数在1和-1之间交替.会导致索引除数在2和-2之间交替,这会导致索引从一端到另一端交替i增加.序列是a[0],a[-1],a[1],a[-2],a[2],a[-3],等.

(我迭代i,a因为在这种情况下,每个值a都等于它的索引.通常,迭代range(len(a)).)


MSe*_*ert 5

你问题背后的基本原理是所谓的roundrobin算法.该itertools-documentation页包含了可能实现的吧:

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))
Run Code Online (Sandbox Code Playgroud)

所以你要做的就是将你的列表分成两个子列表,一个从左端开始,一个从右端开始:

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]
Run Code Online (Sandbox Code Playgroud)

或者,您可以创建一个更长的列表(包含从左到右的序列中的交替项目以及从右到左的完整序列的项目),并且只采用相关元素:

list(roundrobin(a, reversed(a)))[:len(a)]
Run Code Online (Sandbox Code Playgroud)

或者将其用作显式生成器next:

rr = roundrobin(a, reversed(a))
[next(rr) for _ in range(len(a))]
Run Code Online (Sandbox Code Playgroud)

或@Tadhg McDonald-Jensen建议的快速变体(谢谢!):

list(islice(roundrobin(a,reversed(a)),len(a)))
Run Code Online (Sandbox Code Playgroud)