# NumPy 筆記:平移陣列元素
> 作者:王一哲
> 日期:2019/1/14
</br>
## 前言
今天學生問了一個好玩的問題:**如果使用已經建立了一個二維陣列,要怎麼做才能將所有的元素向某個方向平移?**以下是我找到的作法,請注意,以下的程式碼都省略了 **import numpy as np**。
</br>
## 方法1:使用索引取出元素
### 產生陣列
首先我們產生一個 $9 \times 8$ 的陣列,為了一眼就看出每個元素原來的位置,我將第0列皆設定為個位數,第1列皆為1開頭,其餘依此類推。
```python
m, n = 9, 8
a = np.zeros(m * n).reshape(m, n)
for i in range(m):
for j in range(n):
a[i][j] = i * 10 + j
print(a)
```
輸出為
```python
[[ 0. 1. 2. 3. 4. 5. 6. 7.]
[10. 11. 12. 13. 14. 15. 16. 17.]
[20. 21. 22. 23. 24. 25. 26. 27.]
[30. 31. 32. 33. 34. 35. 36. 37.]
[40. 41. 42. 43. 44. 45. 46. 47.]
[50. 51. 52. 53. 54. 55. 56. 57.]
[60. 61. 62. 63. 64. 65. 66. 67.]
[70. 71. 72. 73. 74. 75. 76. 77.]
[80. 81. 82. 83. 84. 85. 86. 87.]]
```
我們先練習一下取值的方法,如果想要印出陣列中每一列索引值為1到最後1個的元素,語法為
```python
print(a[::, 1:])
```
輸出為
```python
[[ 1. 2. 3. 4. 5. 6. 7.]
[11. 12. 13. 14. 15. 16. 17.]
[21. 22. 23. 24. 25. 26. 27.]
[31. 32. 33. 34. 35. 36. 37.]
[41. 42. 43. 44. 45. 46. 47.]
[51. 52. 53. 54. 55. 56. 57.]
[61. 62. 63. 64. 65. 66. 67.]
[71. 72. 73. 74. 75. 76. 77.]
[81. 82. 83. 84. 85. 86. 87.]]
```
如果想要印出陣列中每一列索引值為0的元素,語法為
```python
print(a[::, 0])
```
輸出為
```python
[ 0. 10. 20. 30. 40. 50. 60. 70. 80.]
```
</br>
### 向左平移1格
我們先產生一個新的陣列 left,用來儲存平移後的資料,再利用索引值將平移後的元素填入對應的位置,語法為
```python
left = np.zeros(m * n).reshape(m, n)
left[::, 0:-1] = a[::, 1:]
left[::, -1] = a[::, 0]
print(left)
```
輸出為
```python
[[ 1. 2. 3. 4. 5. 6. 7. 0.]
[11. 12. 13. 14. 15. 16. 17. 10.]
[21. 22. 23. 24. 25. 26. 27. 20.]
[31. 32. 33. 34. 35. 36. 37. 30.]
[41. 42. 43. 44. 45. 46. 47. 40.]
[51. 52. 53. 54. 55. 56. 57. 50.]
[61. 62. 63. 64. 65. 66. 67. 60.]
[71. 72. 73. 74. 75. 76. 77. 70.]
[81. 82. 83. 84. 85. 86. 87. 80.]]
```
</br>
### 向右平移1格
我們先產生一個新的陣列 right,用來儲存平移後的資料,再利用索引值將平移後的元素填入對應的位置,語法為
```python
right = np.zeros(m * n).reshape(m, n)
right[::, 1:] = a[::, 0:-1]
right[::, 0] = a[::, -1]
print(right)
```
輸出為
```python
[[ 7. 0. 1. 2. 3. 4. 5. 6.]
[17. 10. 11. 12. 13. 14. 15. 16.]
[27. 20. 21. 22. 23. 24. 25. 26.]
[37. 30. 31. 32. 33. 34. 35. 36.]
[47. 40. 41. 42. 43. 44. 45. 46.]
[57. 50. 51. 52. 53. 54. 55. 56.]
[67. 60. 61. 62. 63. 64. 65. 66.]
[77. 70. 71. 72. 73. 74. 75. 76.]
[87. 80. 81. 82. 83. 84. 85. 86.]]
```
</br>
### 向上平移1格
我們先產生一個新的陣列 top,用來儲存平移後的資料,再利用索引值將平移後的元素填入對應的位置,語法為
```python
top = np.zeros(m * n).reshape(m, n)
top[0:-1, ::] = a[1:, ::]
top[-1, ::] = a[0, ::]
print(top)
```
輸出為
```python
[[10. 11. 12. 13. 14. 15. 16. 17.]
[20. 21. 22. 23. 24. 25. 26. 27.]
[30. 31. 32. 33. 34. 35. 36. 37.]
[40. 41. 42. 43. 44. 45. 46. 47.]
[50. 51. 52. 53. 54. 55. 56. 57.]
[60. 61. 62. 63. 64. 65. 66. 67.]
[70. 71. 72. 73. 74. 75. 76. 77.]
[80. 81. 82. 83. 84. 85. 86. 87.]
[ 0. 1. 2. 3. 4. 5. 6. 7.]]
```
</br>
### 向下平移1格
我們先產生一個新的陣列 bottom,用來儲存平移後的資料,再利用索引值將平移後的元素填入對應的位置,語法為
```python
bottom = np.zeros(m * n).reshape(m, n)
bottom[1:, ::] = a[0:-1, ::]
bottom[0, ::] = a[-1, ::]
print(bottom)
```
輸出為
```python
[[80. 81. 82. 83. 84. 85. 86. 87.]
[ 0. 1. 2. 3. 4. 5. 6. 7.]
[10. 11. 12. 13. 14. 15. 16. 17.]
[20. 21. 22. 23. 24. 25. 26. 27.]
[30. 31. 32. 33. 34. 35. 36. 37.]
[40. 41. 42. 43. 44. 45. 46. 47.]
[50. 51. 52. 53. 54. 55. 56. 57.]
[60. 61. 62. 63. 64. 65. 66. 67.]
[70. 71. 72. 73. 74. 75. 76. 77.]]
```
</br>
### 同時向左、向上各平移1格
我們先產生一個新的陣列 top_left,用來儲存平移後的資料,再利用索引值將平移後的元素填入對應的位置,語法為
```python
top_left = np.zeros(m * n).reshape(m, n)
top_left[0:-1, 0:-1] = a[1:, 1:] # 將陣列a第1列、第1行到右下角的元素填到top_left的左上角
top_left[-1, -1] = a[0, 0] # 將陣列a左上角的元素填到top_left的右下角
top_left[-1, 0:-1] = a[0, 1:] # 將陣列a第0列中除了索引值為1到最後的元素填到top_left的最後1列
top_left[0:-1, -1] = a[1:, 0] # 將陣列a第1列到最後1列中索引值為0的元素填到top_left的最後1行
print(top_left)
```
輸出為
```python
[[11. 12. 13. 14. 15. 16. 17. 10.]
[21. 22. 23. 24. 25. 26. 27. 20.]
[31. 32. 33. 34. 35. 36. 37. 30.]
[41. 42. 43. 44. 45. 46. 47. 40.]
[51. 52. 53. 54. 55. 56. 57. 50.]
[61. 62. 63. 64. 65. 66. 67. 60.]
[71. 72. 73. 74. 75. 76. 77. 70.]
[81. 82. 83. 84. 85. 86. 87. 80.]
[ 1. 2. 3. 4. 5. 6. 7. 0.]]
```
</br>
## 方法2:使用 numpy.roll
numpy.roll 的語法為
```python
numpy.roll(陣列, 移動格數, axis = 0 或 1)
```
若 axis = 0 會縱向移動,若 axis = 1 會橫向移動。詳細的說明請參考官方說明書[numpy.roll](https://docs.scipy.org/doc/numpy-1.15.1/reference/generated/numpy.roll.html)。以下我們改用 numpy.roll 再做一次平移,由於這樣的寫法與方法1的寫法效果相同,故省略輸出結果。
### 向左平移1格
```python
left_roll = np.roll(a, -1, axis = 1)
print(left_roll)
```
</br>
### 向右平移1格
```python
right_roll = np.roll(a, 1, axis = 1)
print(right_roll)
```
</br>
### 向上平移1格
```python
top_roll = np.roll(a, -1, axis = 0)
print(top_roll)
```
</br>
### 向下平移1格
```python
bottom_roll = np.roll(a, 1, axis = 0)
print(bottom_roll)
```
</br>
### 同時向左、向上各平移1格
```python
roll = np.roll(a, -1, axis = 0)
roll = np.roll(roll, -1, axis = 1)
print(roll)
```
</br>
## 結語
當我聽到這個問題時,第一個想法是用索引值取出元素再存入對應的位置,也就是方法1。但是我覺得 Numpy 可能有已經寫好的工具,果然搜尋一下就找到了 numpy.roll,Numpy 的工具果然很齊全。
---
###### tags:`Python`