保留两个,跳过 Python 列表中的两个

Keep two, skip two in Python list

我有一个Python列表

num_list = list(range(1,33))

并且需要列表中的每隔一对数字,如下所示:

[1, 2, 5, 6, 9, 10 ... ]

我已经想出如何从列表中排除某些索引,就像这样

num_list[2::3]

> [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]

但还没有想出如何让它一次捕获两个索引。

您不能仅通过一次切片操作来完成此操作。你可以做类似

的事情
[num_list[j] for i in range(0, len(num_list), 4) for j in (i, i+1)]

编辑:另一个选项是:

[x for i in range(0, len(num_list), 4) for x in num_list[i:i+2]]

还有一个(懒惰的)选项是

def keep_two_skip_two(it):
    it = iter(it)
    try:
        while True:
            yield next(it)
            yield next(it)
            next(it)
            next(it)
    except StopIteration:
        return

list(keep_two_skip_two(num_list))

您可以使用 enumerate,然后以数学方式过滤索引:

[v for i, v in enumerate(num_list) if i % 4 < 2]

针对您的情况的另一种解决方案是将列表理解与切片和压缩相结合。切片只提取需要的值,压缩将它们成对组合在一起,在列表理解中,您可以迭代这些对以形成最终输出。在代码中,它是 ,like

[p for pairs in zip(num_list[::4],num_list[1::4]) for p in pairs]

这里有一个实用的方法,可以在 sliced 列表中使用 itertools.chain.from_iterable along with zip 实现此目的:

>>> num_list = list(range(1,33))
>>> from itertools import chain

>>> list(chain.from_iterable(zip(num_list[::4], num_list[1::4])))
[1, 2, 5, 6, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30]

解决方案 1: 使用两个排除:

del num_list[2::4]
del num_list[2::3]

现在您的列表是:

[1, 2, 5, 6, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30]

解决方案 2: 使用 compresscycle 来自 itertools

list(compress(num_list, cycle([True, True, False, False]))))

较短的版本:

[*compress(num_list, cycle([1, 1, 0, 0]))]

您可以将列表切片两次,然后对其进行排序。

sorted(num_list[0::4]+num_list[1::4])

您可以根据您的模式看起来更通用一些。您可以应用掩码,而不是使用基于索引的条件。例如

mask = [1, 1, 0, 0]

要创建值重复的掩码,使其与数据的长度相同,您可以 zip 数据与 itertools.cycle(m) 并排。示例:

import itertools


def filter_mask(data, mask):
    return [d for d, m in zip(data, itertools.cycle(mask)) if m]

或按照 @KellyBundy 建议使用压缩!

def filter_mask(data, mask):
    return list(itertools.compress(data, itertools.cycle(mask)))

示例

>>> data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> filter_mask(data, mask=[1, 0])
[0, 2, 4, 6, 8, 10]
>>> filter_mask(data, mask=[0, 1])
[1, 3, 5, 7, 9]
>>> filter_mask(data, mask=[1, 1, 0, 0])
[0, 1, 4, 5, 8, 9]
>>> filter_mask(data, mask=[1, 0, 1, 1, 0])
[0, 2, 3, 5, 7, 8, 10]

对两个生成器使用不同的 range 对象:

>>> [x for i in range(1,33,4) for x in range(i, i+2)]
[1, 2, 5, 6, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30]

仅按需生成 2 元素范围的惰性版本:

>>> from itertools import chain
>>> x = chain.from_iterable(range(i, i+2) for i in range(1,33,4))
>>> list(x)
[1, 2, 5, 6, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30]