我正在尝试实现一个函数,该函数将在numpy 2d数组中的特定元素移位给定方向上所需数量的空格。空格应填充0。此函数将输入一个numpy数组,x和y坐标,所需方向以及要移位的空格数。
例如,shift是假设函数:
arr = np.array([1, 1, 1], [1, 1, 1], [1, 1, 1])
arr out: [[1, 1, 1],
[1, 1, 1],
[1, 1, 0]]
shift(arr, 0, 0, 'right', 2)
arr out: [[0, 0, 1],
[1, 1, 1],
[1, 1, 0]]
shift(arr, 0, 2, 'down', 1)
arr out: [[0, 0, 0],
[1, 1, 1],
[1, 1, 1]]
我发现我可以使用numpy的滚动功能实现沿着该行或列的行或列的所有元素的所需移位。但是,这种方法只是将元素循环回到同一行或列的开头,并且不会用0' s填充空格。例如:
arr[:, 0] = np.roll(arr[:, 0], 1)
arr out: [[1, 0, 0],
[0, 1, 1],
[1, 1, 1]]
非常感谢任何帮助。
编辑:x和y坐标是要在2d数组内移位的元素的坐标。然后,相同行或列内的其余元素相对于该元素在期望方向上移位。例如,shift(arr,2,2,' down',1)将列中的元素相对于(2,2)处的元素向下移动1.所有输入值可以假设为始终有效。
编辑:此问题与链接的问题不同,元素相对于提供的坐标处的元素移位,并且此移位发生在嵌套数组中。此外,该解决方案不允许在同一列内向上或向下移动元素。
答案 0 :(得分:1)
这是一个或多或少全面的功能来解决它:
import numpy as np
arr = np.arange(25).reshape((5, 5))
print(arr)
# [[ 0 1 2 3 4]
# [ 5 6 7 8 9]
# [10 11 12 13 14]
# [15 16 17 18 19]
# [20 21 22 23 24]]
print(shift(arr, 2, 1, 'up', 2))
# [[ 0 11 2 3 4]
# [ 5 0 7 8 9]
# [10 0 12 13 14]
# [15 16 17 18 19]
# [20 21 22 23 24]]
print(shift(arr, 2, 1, 'left', -2))
# [[ 0 1 2 3 4]
# [ 5 6 7 8 9]
# [10 0 0 11 12]
# [15 16 17 18 19]
# [20 21 22 23 24]]
print(shift(arr, 2, 1, 'down', 1, fill=100))
# [[ 0 1 2 3 4]
# [ 5 6 7 8 9]
# [ 10 100 12 13 14]
# [ 15 11 17 18 19]
# [ 20 16 22 23 24]]
shift(arr, 2, 1, 'right', 3, inplace=True)
print(arr)
# [[ 0 1 2 3 4]
# [ 5 6 7 8 9]
# [10 0 0 0 11]
# [15 16 17 18 19]
# [20 21 22 23 24]]
一些测试:
import numpy as np
def shift_vector(v, i, n, empty=0):
if n < 0:
return shift_vector(v[::-1], len(v) - i - 1, -n)[::-1]
if n < len(v) - i:
# Find n empty places after i
idx = np.where(np.cumsum(v[i + 1:] == empty) == n)[0]
last_zero_idx = idx[0] if len(idx) > 0 else len(v) - i - 1
# Get non-empty values
v_slice = v[i + 1:i + last_zero_idx + 1]
values = v_slice[np.where(v_slice != empty)[0]]
# Copy to vector
v[i + n] = v[i]
r = range(i + n + 1, min(i + last_zero_idx + 2, len(v)))
v[r] = values[:len(r)]
v[i:i + n] = empty
return v
def shift(a, i, j, dir, n, empty=0, inplace=False):
out = a
if not inplace:
out = a.copy()
if dir == 'down':
out[:, j] = shift_vector(out[:, j], i, n, empty=empty)
elif dir == 'up':
out[:, j] = shift_vector(out[:, j], i, -n, empty=empty)
elif dir == 'right':
out[i, :] = shift_vector(out[i, :], j, n, empty=empty)
elif dir == 'left':
out[i, :] = shift_vector(out[i, :], j, -n, empty=empty)
else:
raise ValueError('Unknown direction "{}".'.format(dir))
return out
m = np.array([[1, 0, 0, 2],
[3, 4, 0, 0],
[5, 0, 6, 7],
[0, 8, 9, 0]])
print("m")
print(m)
print("shift(m, 1, 0, 'right', 2)")
print(shift(m, 1, 0, 'right', 2))
print("shift(m, 3, 1, 'down', -2)")
print(shift(m, 3, 1, 'down', -2))
print("shift(m, 0, 3, 'left', 3)")
print(shift(m, 0, 3, 'left', 3))
print("shift(m, 2, 2, 'up', 1)")
print(shift(m, 2, 2, 'up', 1))
修改的
在评论中讨论后,我添加了另一个函数来解决移动“滑动瓷砖”的问题:
m
[[1 0 0 2]
[3 4 0 0]
[5 0 6 7]
[0 8 9 0]]
shift(m, 1, 0, 'right', 2)
[[1 0 0 2]
[0 0 3 4]
[5 0 6 7]
[0 8 9 0]]
shift(m, 3, 1, 'down', -2)
[[1 4 0 2]
[3 8 0 0]
[5 0 6 7]
[0 0 9 0]]
shift(m, 0, 3, 'left', 3)
[[2 0 0 0]
[3 4 0 0]
[5 0 6 7]
[0 8 9 0]]
shift(m, 2, 2, 'up', 1)
[[1 0 0 2]
[3 4 6 0]
[5 0 0 7]
[0 8 9 0]]
输出:
{{1}}
答案 1 :(得分:0)
只需滚动然后将已旋转的数据清零:
# Let direction = "down" and col = 0, n = 2
In [1]: i
Out[1]:
array([[1., 0., 0.],
[1., 1., 1.],
[0., 0., 1.]])
In [2]: i[:, col] = np.roll(i[:, col], n)
In [3]: i[:n, col] = 0
In [4]: i
Out[4]:
array([[0., 0., 0.],
[0., 1., 1.],
[1., 0., 1.]])
您需要为其他三个方向实施等效版本,但它只是这两行的变体。