At the risk of duplicating my previous answer, I'll try to illustrate the problem with doing an in-place shuffle without any sort of copy.
Your sample:
In [196]: arr = np.array([10, 20, 30, 40, 50])
...: idx = [1, 0, 3, 4, 2]
The straightforward approach:
In [197]: arr[idx]
Out[197]: array([20, 10, 40, 50, 30])
Effectively it is doing:
In [198]: [arr[1],arr[0],arr[3],arr[4],arr[2]]
Out[198]: [20, 10, 40, 50, 30]
A naive iterative approach:
In [199]: for i,v in enumerate(idx):
...: arr[i] = arr[v]
...:
In [200]: arr
Out[200]: array([20, 20, 40, 50, 40])
Oops - that has stepped on values. arr[1] has been copied to [0]. That is then copied [1]. The 10 and 30 have been lost.
The iterative solution requires a copy:
In [201]: arr = np.array([10, 20, 30, 40, 50])
...: idx = [1, 0, 3, 4, 2]
In [202]: arr1 = arr.copy()
...: for i,v in enumerate(idx):
...: arr[i] = arr1[v]
...:
In [203]: arr
Out[203]: array([20, 10, 40, 50, 30])
In [205]: arr[idx]=arr
In [206]: arr
Out[206]: array([10, 10, 30, 30, 30])
It may be possible to come up with an indexing that avoids this, but it would take some thought. I suspect old classical computer science (Knuth?) worked this out, since old computers has much smaller RAM, and often depended on values read serially from tape.
Other indexing attempts:
In [205]: arr[idx]=arr
In [206]: arr
Out[206]: array([10, 10, 30, 30, 30])
In [207]: arr = np.array([10, 20, 30, 40, 50])
...: idx = [1, 0, 3, 4, 2]
In [208]: arr[idx]=arr.copy()
In [209]: arr
Out[209]: array([20, 10, 50, 30, 40])