我有一个元素数组,例如 r = np.arange(15)
。我正在尝试将此数组拆分为连续元素的块,其中每个块(可能是最后一个块除外)的大小为 M
并且每对块之间有 m
重复元素。
例如:split_to_chunks(np.arange(15), M=5, m=1)
应该产生四个列表:[0, 1, 2, 3, 4]
、[4, 5, 6, 7, 8]
、[8, 9, 10, 11, 12]
、[12, 13, 14]
显然这可以迭代地完成,但我正在寻找一种更“pythonic”(和更快)的方式来做到这一点。
回答1
像这样的列表理解:
[l[i*(M-m):i*(M-m)+M] for i in range(math.ceil((len(l)-m)/(M-m)))]
例子:
import math
l = list(range(15))
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
m, M = 2, 5
[l[i*(M-m):i*(M-m)+M] for i in range(math.ceil((len(l)-m)/(M-m)))]
# [[0, 1, 2, 3, 4],
# [3, 4, 5, 6, 7],
# [6, 7, 8, 9, 10],
# [9, 10, 11, 12, 13],
# [12, 13, 14]]
m, M = 3, 5
[l[i*(M-m):i*(M-m)+M] for i in range(math.ceil((len(l)-m)/(M-m)))]
# [[0, 1, 2, 3, 4],
# [2, 3, 4, 5, 6],
# [4, 5, 6, 7, 8],
# [6, 7, 8, 9, 10],
# [8, 9, 10, 11, 12],
# [10, 11, 12, 13, 14]]
l = range(5)
m, M = 2, 3
[l[i*(M-m):i*(M-m)+M] for i in range(math.ceil((len(l)-m)/(M-m)))]
# [range(0, 3), range(1, 4), range(2, 5)]
解释:
块 i
从索引 i*(M-m)
开始,并在后面的 M 个位置结束索引 i*(M-m) + M
。
chunk index starts ends
-------------------------------------------------
0 0 M
1 M-m M-m+M = 2*M-m
2 2*M-m-m=2(M-m) 2*(M-m)+M = 3M-2m
...
现在的问题是确定有多少块。
在每一步中,我们将初始索引增加 M-m
,因此要计算总步数,我们需要将列表的长度除以 M-m
(但在减去 m
之后,因为在第一个块中我们不是跳过任何东西)。
最后,使用上限函数添加最后一个不完整的块,以防划分不准确。
回答2
这应该做的工作:
def split_to_chunks(r, M=5, m=1):
return [r[i*(M-m): (i+1)*M-i*m] for i in range(len(r)//(M-m)+1) if i*(M-m) < len(r)]
说明:在列表理解循环中以问题中解释的方式遍历索引。块的每个开始都将从 i*(M-m)
开始并在 (i+1)*M-i*m
结束。最后,如果块的开始在数组长度之后,它将跳过它。