编辑:
这是一个基本相同的算法版本,但没有任何循环:
def snake_matrix(n):
# Make sequences: [0, 0, 1, 0, 1, 2, 0, 1, 2, 3, ...]
i = np.arange(n)
c = np.cumsum(i)
reps = np.repeat(c, i + 1)
seqs = np.arange(len(reps)) - reps
# Make inverted sequences: [0, 1, 0, 2, 1, 0, 3, 2, 1, 0, ...]
i_rep = np.repeat(i, i + 1)
seqs_inv = i_rep - seqs
# Select sequences for row and column indices
seq_even_mask = (i_rep % 2 == 0)
# Row inverts even sequences
row = np.where(seq_even_mask, seqs, seqs_inv)
# Column inverts odd sequences
col = np.where(~seq_even_mask, seqs, seqs_inv)
# Mirror for lower right corner
row = np.concatenate([row, n - 1 - row[len(row) - n - 1::-1]])
col = np.concatenate([col, n - 1 - col[len(col) - n - 1::-1]])
m = np.empty((n, n), dtype=int)
m[row, col] = np.arange(n * n)
return m
有趣的是,经过几次基准测试后,似乎根据大小,这可能会或可能不会比以前的算法快。
这是使用 NumPy 的另一种解决方案。我不知道是否有任何其他方法可以使它变得更好(没有循环,或者在这种情况下是列表推导),但至少它不会遍历每个元素。不过,这仅适用于方阵。
import numpy as np
def snake_matrix(n):
# Sequences for indexing top left triangle: [0], [0, 1], [0, 1, 2], [0, 1, 2, 3]...
seqs = [np.arange(i + 1) for i in range(n)]
# Row indices reverse odd sequences
row = np.concatenate([seq if i % 2 == 0 else seq[::-1] for i, seq in enumerate(seqs)])
# Column indices reverse even sequences
col = np.concatenate([seq if i % 2 == 1 else seq[::-1] for i, seq in enumerate(seqs)])
# Indices for bottom right triangle "mirror" top left triangle
row = np.concatenate([row, n - 1 - row[len(row) - n - 1::-1]])
col = np.concatenate([col, n - 1 - col[len(col) - n - 1::-1]])
# Make matrix
m = np.empty((n, n), dtype=int)
m[row, col] = np.arange(n * n)
return m
print(snake_matrix(6))
输出:
[[ 0 2 3 9 10 20]
[ 1 4 8 11 19 21]
[ 5 7 12 18 22 29]
[ 6 13 17 23 28 30]
[14 16 24 27 31 34]
[15 25 26 32 33 35]]
在OEIS A319571 sequence 中有更多关于这种枚举的信息(虽然这指的是无限网格的一般序列,在这种情况下,您将有一个枚举从左上角开始,另一个枚举在右下角) .