import numpy as np
A = np.asarray([[0, 1, 2],
[2, 0, 1],
[1, 2, 0]])
col_idxs = np.asarray([2, 1, 1])
row_idxs = np.arange(len(A))
a = A[:, 0].copy()
A[:, 0] = A[row_idxs, col_idxs]
A[row_idxs, col_idxs] = a
or more concisely
c = np.asarray([2, 1, 1])
r = np.arange(len(A))
A[:, 0], A[r, c] = A[r, c], A[:, 0].copy()
Here we make use of the fact that we can index individual elements of a numpy array by supplying it two separate list-like objects for the corresponding row and col indexes.
So the line A[:, 0], A[r, c] = A[r, c], A[:, 0].copy() can be read as get the indexed elements from each column and swap them with the first column.
Edit
Thanks to @Paul Panzer for his comment, the assignment can be made even shorter by writing it as A[r, c], A[:, 0] = A[:, 0], A[r, c].
Note that the order of assignment to A[r, c] and A[:, 0] has been change compared to the earlier version.
The reason the copy can be omitted here is because
- In an assignment, the right hand side is evaluated fully before
assigning to the variables on the left.
- Fancy indexing of Numpy (
A[r, c] here) returns a copy unlike
slices (A[:, 0]) which returns a view.
Therefore, what this new line of code says is
- Get a view (i.e., reference) to the the first column of
A
- Create a copy of
A[r, c]. The copy is implicit because of fancy indexing of Numpy array.
- Assign
A[r, c] the values of the first column of A using the
view of that column.
- Assign the first column of
A the copy of A[r, c] we made earlier
(note that by this point A[r, c] has already been assigned the old
value of A[:, 0].)
Also, we don't need to convert the indexes to Numpy array.
c = [2, 1, 1]
r = range(len(A))
A[r, c], A[:, 0] = A[:, 0], A[r, c]
x[[0, 1, 2], [2, 1, 1]], x[[0, 1, 2], [0, 0, 0]] = x[[0, 1, 2], [0, 0, 0]], x[[0, 1, 2], [2, 1, 1]]