python - 移动 Numpy 数组中的元素

标签 python numpy

我正在尝试实现一个函数,它将 numpy 二维数组中的特定元素在给定方向上移动所需的空格数。空格应该用 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 的 roll 函数实现行或列的所有元素沿该行或列的所需移动。然而,这种方法只是将元素循环回到同一行或同一列的开头,并且不会用 0 填充空白。例如:

arr[:, 0] = np.roll(arr[:, 0], 1)
arr out: [[1, 0, 0],
          [0, 1, 1],
          [1, 1, 1]]

非常感谢任何帮助。

编辑:x 和 y 坐标是二维数组中要移动的元素的坐标。然后,同一行或同一列内的其余元素相对于该元素沿所需方向移动。例如,shift(arr, 2, 2, 'down', 1) 将列中的元素相对于 (2, 2) 处的元素向下移动 1。可以假定所有输入值始终有效。

编辑:此问题与链接的问题不同,因为元素相对于提供的坐标处的元素进行了移动,并且这种移动发生在嵌套数组中。此外,该解决方案不允许在同一列内向上或向下移动元素。

最佳答案

这里有一个或多或少的综合函数来解决这个问题:

def shift(a, i, j, dir, n, fill=0, inplace=False):
    out = a
    if not inplace:
        out = a.copy()
    if dir == 'down':
        if n < 0:
            return shift(out, i, j, 'up', -n, fill=fill, inplace=True)
        n = min(n, a.shape[0] - i)
        out[i+n:, j] = a[i:a.shape[0] - n, j]
        out[i:i+n, j] = fill
    elif dir == 'up':
        if n < 0:
            return shift(out, i, j, 'down', -n, fill=fill, inplace=True)
        n = min(n, i+1)
        out[:i+1-n, j] = a[n:i+1, j]
        out[i+1-n:i+1, j] = fill
    elif dir == 'right':
        if n < 0:
            return shift(out, i, j, 'left', -n, fill=fill, inplace=True)
        n = min(n, a.shape[1] - j)
        out[i, j+n:] = a[i, j:a.shape[1] - n]
        out[i, j:j+n] = fill
    elif dir == 'left':
        if n < 0:
            return shift(out, i, j, 'right', -n, fill=fill, inplace=True)
        n = min(n, j+1)
        out[i, :j+1-n] = a[i, n:j+1]
        out[i, j+1-n:j+1] = fill
    else:
        raise ValueError('Unknown direction "{}".'.format(dir))
    return out

一些测试:

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]]

关于python - 移动 Numpy 数组中的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49223183/

相关文章:

python - 如何使用 Gstreamer 制作有问题的视频?

python - 解析过程中随时列出所有可用标记的解析技术

python - 根据现有列的分类值将列添加到数据框

python - 在代码中查找 numpy RuntimeWarning 的位置

python - 如何使用numpy的asarray函数在Python中读取 boolean 数据文件

c - 如何在 Cython 中动态声明二维 c 数组

python - python (commands.getoutput) 无法识别带别名的 Linux 命令

python - Python 中的无效 URL (POST/v1/chat/completions) 错误

python - 使用 numpy loadtxt

python - 如何在有条件的情况下在 ndarray 上使用 numpy.mean() ?