给定二维矩阵,例如
l = [[1,1,1],
[2,5,2],
[3,3,3]])
对列和行实施移位操作的最有效方法是什么?
E.g。
shift('up', l)
[[2, 5, 2],
[3, 3, 3],
[1, 1, 1]]
但
shift('left', l)
[[1, 1, 1],
[5, 2, 2],
[3, 3, 3]]
由于this answer,我在两个深度使用collections.deque
但是'up'或'down'只需要1个班次,'left'或'right'需要N个班次(my实现是为每一行使用for循环。)
在C中我认为可以使用指针算法来改进(参见例如this answer)。
有更好的pythonic方式吗?
修改
感谢martineau指出了问题的这些重点。 对不起,我之前没有指出过它们。
答案 0 :(得分:26)
Numpy提供了一个名为roll()的方法来移动条目。
>>> import numpy as np
>>> x = np.arange(9)
>>> x = x.reshape(3, 3)
>>> print(x)
[[0 1 2]
[3 4 5]
[6 7 8]]
>>> x = np.roll(x, -1, axis=0) # up
>>> print(x)
[[3 4 5]
[6 7 8]
[0 1 2]]
>>> x = np.roll(x, 1, axis=0) # down
>>> print(x)
[[0 1 2]
[3 4 5]
[6 7 8]]
>>> x = np.roll(x, 2, axis=1) # right
>>> print(x)
[[1 2 0]
[4 5 3]
[7 8 6]]
>>> x = np.roll(x, -2, axis=1) # left
>>> print(x)
[[0 1 2]
[3 4 5]
[6 7 8]]
我认为与大多数解决方案相比,Numpy将非常有效 在矩阵运算方面,您不会受到二维矩阵的约束。
答案 1 :(得分:2)
这是一种非常有效的方法,可以使用非方形矩阵:
DIRS = NONE, UP, DOWN, LEFT, RIGHT = 'unshifted', 'up', 'down', 'left', 'right'
def shift(matrix, direction, dist):
""" Shift a 2D matrix in-place the given distance of rows or columns in the
specified (NONE, UP, DOWN, LEFT, RIGHT) direction and return it.
"""
if dist and direction in (UP, DOWN, LEFT, RIGHT):
n = 0
if direction in (UP, DOWN):
n = (dist % len(matrix) if direction == UP else -(dist % len(matrix)))
elif direction in (LEFT, RIGHT):
n = (dist % len(matrix[0]) if direction == LEFT else -(dist % len(matrix[0])))
matrix[:] = list(zip(*matrix)) # Transpose rows and columns for shifting.
h = matrix[:n]
del matrix[:n]
matrix.extend(h)
if direction in (LEFT, RIGHT):
matrix[:] = map(list, zip(*matrix)) # Undo previous transposition.
return matrix
if __name__ == '__main__':
# Some non-square test matrices.
matrix1 = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]]
matrix2 = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]]
def shift_and_print(matrix, direction, dist):
GAP = 2 # Plus one for a ":" character.
indent = max(map(len, DIRS)) + GAP
print(direction
+ ': ' + (indent-2-len(direction))*' '
+ ('\n'+indent*' ').join(map(str, shift(matrix, direction, dist)))
+ '\n')
for matrix in matrix1, matrix2:
for direction in DIRS:
shift_and_print(matrix, direction, 1) # Printed results are cumulative.
输出(注意,结果是累积的,因为操作是就地执行的,并且移位应用于上一次调用的结果):
no shift: [1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10, 11, 12]
up: [4, 5, 6]
[7, 8, 9]
[10, 11, 12]
[1, 2, 3]
down: [1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10, 11, 12]
left: [2, 3, 1]
[5, 6, 4]
[8, 9, 7]
[11, 12, 10]
right: [1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10, 11, 12]
no shift: [1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]
up: [5, 6, 7, 8]
[9, 10, 11, 12]
[1, 2, 3, 4]
down: [1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]
left: [2, 3, 4, 1]
[6, 7, 8, 5]
[10, 11, 12, 9]
right: [1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]
答案 2 :(得分:0)
使用numpy
可能是这样的:
def shift(x, direction='up'):
if direction == 'up':
temp = range(x.shape[0])
indicies = temp[1:] + [temp[0]]
return x[indicies]
elif direction == 'left':
temp = range(x.shape[1])
indicies = temp[1:] + [temp[0]]
return x[:, indicies]
else:
print 'Error direction not known'
结果:
>>> shift(l, direction='up')
array([[2, 5, 2],
[3, 3, 3],
[1, 1, 1]])
>>> shift(l, direction='left')
array([[1, 1, 1],
[5, 2, 2],
[3, 3, 3]])
>>> shift(l, direction='to the moon')
Error direction not known
答案 3 :(得分:0)
这是一个通用版本,您可以在任意次数的所有四个方向上旋转
l = [[1,1,1],
[2,5,2],
[3,3,3]]
def shift(direction, count, myList):
myLen = len(myList)
if direction == "up":
return [myList[i % myLen] for i in range(count, count + myLen)]
elif direction == "down":
return [myList[-i] for i in range(count, count - myLen, -1)]
elif direction == "left":
tlist = zip(*myList)
return map(list, zip(*[tlist[i % myLen] for i in range(count, count + myLen)]))
elif direction == "right":
tlist = zip(*myList)
return map(list, zip(*[tlist[-i] for i in range(count, count - myLen, -1)]))
print shift("up", 1, l)
print shift("up", 2, l)
print shift("down", 2, l)
print shift("down", 1, l)
print shift("left", 1, l)
print shift("right", 1, l)
<强>输出强>
[[2, 5, 2], [3, 3, 3], [1, 1, 1]]
[[3, 3, 3], [1, 1, 1], [2, 5, 2]]
[[2, 5, 2], [3, 3, 3], [1, 1, 1]]
[[3, 3, 3], [1, 1, 1], [2, 5, 2]]
[[1, 1, 1], [5, 2, 2], [3, 3, 3]]
[[1, 1, 1], [2, 2, 5], [3, 3, 3]]