Problem
I have a 2D NumPy array, arr, and for each row, I would like to reverse a section of the array. Crucially, for each row, the start and stop indices must be unique. I can achieve this using the following.
import numpy as np
arr = np.repeat(np.arange(10)[np.newaxis, :], 3, axis=0)
reverse = np.sort(np.random.choice(arr.shape[1], [arr.shape[0], 2], False))
# arr
# array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
# reverse
# array([[1, 7],
# [8, 9],
# [4, 6]])
Reverse each row between the start, stop indices in `reverse.
for idx, (i, j) in enumerate(reverse):
arr[idx, i:j+1] = arr[idx, i:j+1][::-1]
# arr
# array([[0, 7, 6, 5, 4, 3, 2, 1, 8, 9],
# [0, 1, 2, 3, 4, 5, 6, 7, 9, 8],
# [0, 1, 2, 3, 6, 5, 4, 7, 8, 9]])
Question
Is this possible using basic slicing and indexing? I tried to use the output of reverse to form multiple slice objects, but was unsuccessful.
Update
A simple comparison of the original method vs answer. For my data, the solution is only required to deal with 2D matrices with shape (50, 100).
import numpy as np
def reverse_one(arr, n):
temp = np.repeat(arr.copy(), n, axis=0)
reverse = np.sort(np.random.choice(temp.shape[1], [n, 2], False))
for idx, (i, j) in enumerate(reverse):
temp[idx, i:j+1] = temp[idx, i:j+1][::-1]
return temp
def reverse_two(arr, n):
temp = np.repeat(arr.copy(), n, axis=0)
reverse = np.sort(np.random.choice(temp.shape[1], [n, 2], False))
rev = np.ravel_multi_index((np.arange(n)[:, np.newaxis], reverse), temp.shape)
rev[:, 1] += 1
idx = np.arange(temp.size).reshape(temp.shape)
s = np.searchsorted(rev.ravel(), idx, 'right')
m = (s % 2 == 1)
g = rev[s[m] // 2]
idx[m] = g[:, 0] - (idx[m] - g[:, 1]) - 1
return temp.take(idx)
m = 100
arr = np.arange(m)[np.newaxis, :]
print("reverse_one:")
%timeit reverse_one(arr, m//2)
print("=" * 40)
print("reverse_two:")
%timeit reverse_two(arr, m//2)
Running the following code in a Jupyter Notebook gives the following results.
reverse_one:
1000 loops, best of 5: 202 µs per loop
========================================
reverse_two:
1000 loops, best of 5: 363 µs per loop
arr[[0,1,2]] = arr[[2,1,0]]instead ofarr[:]=arr[::-1]?