每十个元素从列表中获取两个连续元素

Getting two consecutive elements from a list every ten elements

我有一个列表A,我想获取元素 1、2、11、12、21、22 等作为列表。

比如A = range(100),那么我要[0, 1, 10, 11, 20, 21, ..., 90, 91]

现在我有[num for elem in [[A[i], A[i+1]] for i in range(0, len(A)-1, 10)] for num in elem]

是否有更简洁或更有效的实现方式?

如果你只想要对(如果 101 不在范围内,这将不包括 100)使用 itertools.chain with range and zip (consider using xrange and itertools.izip 以获得更大的 N 值:

itertools.chain(*zip(range(0, N, 10), range(1, N, 10)))

或者使用itertools.chain.from_iterable避免解包:

itertools.chain.from_iterable(zip(range(0, N, 10), range(1, N, 10)))

查看内容:

>>> N = 100
>>> list(itertools.chain(*zip(range(0, N, 10), range(1, N, 10))))
[0, 1, 10, 11, 20, 21, 30, 31, 40, 41, 50, 51, 60, 61, 70, 71, 80, 81, 90, 91]

使用带 enumerate() 的取模运算符按索引过滤。

[elem for idx,elem in enumerate(A) if idx%10 in (0,1)]

怎么样:

[A[i] for i in xrange(0, len(A)) if i%10 in (0, 1)]
[elem for i, elem in enumerate(A) if i %10 in (0, 1)]

使用zip

的另一种方式
[i for t in zip(A[::10],A[1::10]) for i in t]

Logic - 通过一次跳过 10 个来遍历列表中的两个元素,但其中一个从 1 开始,另一个从 0

使用相同的逻辑,您可以尝试itertools.izip(对于Py2用户)

from itertools import izip
[i for t in izip(A[::10],A[1::10]) for i in t]

时间 -

  • zip

    $ python -m timeit -s "A = range(100)" "[i for t in zip(A[::10],A[1::10]) for i in t]"
    100000 loops, best of 3: 1.98 usec per loop
    
  • izip

    $ python -m timeit -s "A = range(100);from itertools import izip" "[i for t in izip(A[::10],A[1::10]) for i in t]"
    1000000 loops, best of 3: 1.79 usec per loop
    

比较其他答案

$ python -m timeit -s "A = range(100)" "[elem for idx,elem in enumerate(A) if idx%10 in (0,1)]"
100000 loops, best of 3: 9.39 usec per loop
$ python -m timeit -s "A = range(100)" "[A[i] for i in xrange(0, len(A)) if i%10 in (0, 1)]"
100000 loops, best of 3: 7.92 usec per loop

izip这里速度很快!

由于 Bhargav Rao 选择 obvious 压缩切片,这里有一个相当简单的协程来执行此操作,因为 filter 只需要两个 True 和八个 [=15] =] 的正确答案:

import itertools # only needed for Python 2
def first_two_of_ten():
    x2, x8 = xrange(2), xrange(8) # use range in Python 3
    yield # gotta queue up a coroutine to send to it
    while True:
        for i in x2:
            yield True
        for i in x8:
            yield False

和用法:

ftot = first_two_of_ten()
next(ftot) # gotta queue the coroutine up

以及itertools.ifilter

的实际使用情况
>>> list(itertools.ifilter(ftot.send, xrange(50)))
[0, 1, 10, 11, 20, 21, 30, 31, 40, 41]

同样,用 range 代替 Python 3 中的 xrange,并且也只使用内置的 filter 代替 Python 3。