保留两个,跳过 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: 使用 compress
和 cycle
来自 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]
我有一个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: 使用 compress
和 cycle
来自 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]