由于问题不清晰,感谢大家的回答!
我的原始问题是,我有一个列表 [1,2,3,4,5,6,7,8],我想选择每个大小为 x,间隔为 1 的块。所以如果我想选择大小为 2 的每个其他块,则结果将为 [1,2,4,5,7,8]。大小为三的块会给我 [1,2,3,5,6,7]。
我在切片方面进行了大量搜索,但找不到选择块而不是元素的方法。执行多个切片操作、拼接和排序似乎有点昂贵。输入可以是 python 列表或 numpy ndarray。提前致谢。
np.in1d()
函数来提取应该省略的索引,然后使用简单的not
运算符获取必须保留的索引。最后,使用简单的布尔索引选择它们:>>> a = np.array([1,2,3,4,5,6,7,8])
>>> range_arr = np.arange(a.size)
>>>
>>> a[~np.in1d(range_arr,range_arr[2::3])]
array([1, 2, 4, 6, 8])
总体方法:
>>> range_arr = np.arange(np_array.size)
>>> np_array[~np.in1d(range_arr,range_arr[chunk::chunk+1])]
a
是一个 NumPy 数组。 - Divakarnp.delete
的方法,它删除了挤压在块之间的单个元素。out = np.delete(A,np.arange(len(A)/(x+1))*(x+1)+x)
这里有另一种基于布尔索引
的方法 -
L = len(A)
avoid_idx = np.arange(L/(x+1))*(x+1)+x
out = np.array(A)[~np.in1d(np.arange(L),avoid_idx)]
样例运行 -
In [98]: A = [51,42,13,34,25,68,667,18,55,32] # Input list
In [99]: x = 2
# Thus, [51,42,13,34,25,68,667,18,55,32]
^ ^ ^ # Skip these
In [100]: np.delete(A,np.arange(len(A)/(x+1))*(x+1)+x)
Out[100]: array([ 51, 42, 34, 25, 667, 18, 32])
In [101]: L = len(A)
...: avoid_idx = np.arange(L/(x+1))*(x+1)+x
...: out = np.array(A)[~np.in1d(np.arange(L),avoid_idx)]
...:
In [102]: out
Out[102]: array([ 51, 42, 34, 25, 667, 18, 32])
>> ll = [1,2,3,4,5,6,7,8]
>> list(itertools.chain(*zip(ll[::3],ll[1::3])))
[1, 2, 4, 5, 7, 8]
ll []
的切片确定块大小,切片步长确定块间距。numpy
解决方案,但它们不一定更快。 转换为数组需要时间开销。list(itertools.chain(*zip(*[ll[i::6] for i in range(3)])))
该函数生成长度为3的块,跳过3个元素。
zip(*)
是将列表的列表“转置”的惯用方式。
itertools.chain(*...)
是将列表的列表“扁平化”的惯用方式。
另一种选择是使用基于项目计数的条件的列表推导。
[v for i,v in enumerate(ll) if i%3]
(0<(i%6)<4)
保留3,跳过3。itertools.chain.from_iterable(...)
是更符合惯用法的方式。从 itertools 中组合 compress 和 cycle 实际上非常快,并且非常容易推广。 - Dunesfrom_iterable
。或者说,在添加那个构造函数之前,我必须学习使用chain(*
。 - hpauljchain(*
的方法,并且很幸运地找到了。但愿也能有一个适用于zip
的方法。 - Dunes使用纯Python解决方案:
假设所需项目为:[yes, yes, no, yes, yes, no, ...]
编码更快,运行较慢:
data = [1, 2, 3, 4, 5, 6, 7, 8]
filtered = [item for i, item in enumerate(data) if i % 3 != 2]
assert filtered == [1, 2, 4, 5, 7, 8]
from itertools import cycle, compress
data = [1, 2, 3, 4, 5, 6, 7, 8]
selection_criteria = [True, True, False]
filtered = list(compress(data, cycle(selection_criteria)))
assert filtered == [1, 2, 4, 5, 7, 8]
[ L[i] for i in range(len(L)) if i%3 != 2 ]
对于大小为n的块
[ L[i] for i in range(len(L)) if i%(n+1) != n ]
这应该能解决问题:
step = 3
size = 2
chunks = len(input) // step
input = np.asarray(input)
result = input[:chunks*step].reshape(chunks, step)[:, :size]
[1,2,5,6]
。例如:[1,2,3,4,5,6,7,8]
->[[1,2], [3,4], [5,6], [7,8]]
->[[1,2], [5,6]]
->[1, 2, 5, 6]
。 - Dunes