1

I want to swap rows in a two-dimensional array. Using advanced slicing is quite convenient for this purpose:

In [50]: l
Out[50]: [[0, 1], [2, 3], [4, 5], [6, 7]]

In [51]: l[::2], l[1::2] = l[1::2], l[::2]

In [52]: l
Out[52]: [[2, 3], [0, 1], [6, 7], [4, 5]]

However, this does not work if I convert the list into Numpy array:

In [60]: arr
Out[60]: 
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7]])

In [61]: arr[::2], arr[1::2] = arr[1::2], arr[::2]

In [62]: arr
Out[62]: 
array([[2, 3],
       [2, 3],
       [6, 7],
       [6, 7]])

Why does this method of swapping not work for Numpy arrays?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Dmytro Prylipko
  • 4,762
  • 2
  • 25
  • 44
  • Are you asking why Numpy arrays handle slicing differently, or are you looking to have the same outcome when using Numpy arrays? *Why is that* is not a very useful question, and too broad to answer here. – Martijn Pieters Jan 22 '19 at 15:27
  • How about? l = list(arr); l[::2], l[1::2] = l[1::2], l[::2]; arr = np.array(l); – sramij Jan 22 '19 at 15:29
  • 2
    @MartijnPieters: I am asking why this particular approach to swapping does work for lists and does not work for numpy arrays. Why is that means 'why they behave differently'. – Dmytro Prylipko Jan 22 '19 at 15:34
  • @DmytroPrylipko: the broad answer is that numpy arrays are not lists. They are matrices and support a much richer indexing syntax. Python lists are one-dimensional beasts, you have list objects inside a list, so you are only dealing with the outer-most list. Numpy arrays are true multi-dimensional matrices, slicing addresses not just rows. – Martijn Pieters Jan 22 '19 at 15:36

1 Answers1

3

Why does this method of swapping not work for numpy arrays?

In short: Numpy arrays are true multidimensional objects and provide views on data. Python list objects are not.

You are only ever indexing one list with l[...], and never the contents of the nested and independent row list objects. Slicing also produces new list objects with references to the nested lists copied to the slice result.

Numpy slicing on the other hand addresses individual cells and series of cells in the whole matrix, and you are given views on the data; you can mutate the result of a numpy array slice and see the changes reflected in the original array.

The latter is what is going wrong for you here; as you assign the second row to the cells of the first row, the reference to the first row cells change with the assignment because they are not a copy but a view, and you end up copying the second row cells back to the second row via the first row.

So if you want to swap rows in a numpy array, you'll have to create a copy first:

source = arr.copy()
arr[::2], arr[1::2] = source[1::2], source[::2]
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343