211

I am surprised this specific question hasn't been asked before, but I really didn't find it on SO nor on the documentation of np.sort.

Say I have a random numpy array holding integers, e.g:

> temp = np.random.randint(1,10, 10)    
> temp
array([2, 4, 7, 4, 2, 2, 7, 6, 4, 4])

If I sort it, I get ascending order by default:

> np.sort(temp)
array([2, 2, 2, 4, 4, 4, 4, 6, 7, 7])

but I want the solution to be sorted in descending order.

Now, I know I can always do:

reverse_order = np.sort(temp)[::-1]

but is this last statement efficient? Doesn't it create a copy in ascending order, and then reverses this copy to get the result in reversed order? If this is indeed the case, is there an efficient alternative? It doesn't look like np.sort accepts parameters to change the sign of the comparisons in the sort operation to get things in reverse order.

0

12 Answers 12

229

temp[::-1].sort() sorts the array in place, whereas np.sort(temp)[::-1] creates a new array.

In [25]: temp = np.random.randint(1,10, 10)

In [26]: temp
Out[26]: array([5, 2, 7, 4, 4, 2, 8, 6, 4, 4])

In [27]: id(temp)
Out[27]: 139962713524944

In [28]: temp[::-1].sort()

In [29]: temp
Out[29]: array([8, 7, 6, 5, 4, 4, 4, 4, 2, 2])

In [30]: id(temp)
Out[30]: 139962713524944
Sign up to request clarification or add additional context in comments.

11 Comments

Thanks, but how does temp[::-1].sort() know that it has to sort in reverse order?? The way I read it is: reverse the original array, and then sort it (in ascending order). Why would reversing the original array (coming in a random order) and then sorting it in ascending order return the array in reversing order?
Is this behaviour documented, as it is pretty unintuitive.
This looks like it works because the [::-1] simply tells numpy to iterate over the array backwards, rather than actually reordering the array. So when the in-place sort happens, it actually sorts in ascending order and moves bits around, but leaves the backwards-iteration part untouched.
With a=np.array((...)) the idiom a[::-1] does not reverse anything, it's just a new view on the same data, more specifically a mirror view. The method a[::-1].sort() operates on the mirrored image, implying that when sort moves left a smaller item in its mirrored image, in reality it is moving it to the right in the real memory block of the a array. The mirrored view is sorted in ascending order, the real data is sorted in descending order. Try it at home by yourself, with some different coins and a mirror!
This really ought to be added as a readable parameter, like np.sort(temp,order='descending') rather than requiring these kinds of hacks
|
186
>>> a=np.array([5, 2, 7, 4, 4, 2, 8, 6, 4, 4])

>>> np.sort(a)
array([2, 2, 4, 4, 4, 4, 5, 6, 7, 8])

>>> -np.sort(-a)
array([8, 7, 6, 5, 4, 4, 4, 4, 2, 2])

6 Comments

Best answer -- short and sweet, and no knowledge of the axis to which np.sort was applied is necessary.
This is different than np.sort(temp)[::-1] in that it places nans at the back of the array instead of the front. Whether that's good or bad is up for debate..
I imagine which placing ofnans is best is dependant on the specific application. So it's good that there's a method for both, one may choose the best for their specific application.
This method did not work for me with a structured array, giving the error numpy.core._exceptions.UFuncTypeError: ufunc 'negative' did not contain a loop with signature matching types dtype([dtype list])
short and sweet answer !! Should be the default answer to this question!
|
21

For short arrays I suggest using np.argsort() by finding the indices of the sorted negatived array, which is slightly faster than reversing the sorted array:

In [37]: temp = np.random.randint(1,10, 10)

In [38]: %timeit np.sort(temp)[::-1]
100000 loops, best of 3: 4.65 µs per loop

In [39]: %timeit temp[np.argsort(-temp)]
100000 loops, best of 3: 3.91 µs per loop

1 Comment

a[np.argsort(-a)] is probably the best approach to any others on this page. No -1 step reversal and one less minus sign to think about.
16

np.flip() and reversed indexed are basically the same. Below is a benchmark using three different methods. It seems np.flip() is slightly faster. Using negation is slower because it is used twice so reversing the array is faster than that.

** Note that np.flip() is faster than np.fliplr() according to my tests.

def sort_reverse(x):
    return np.sort(x)[::-1]

def sort_negative(x):
    return -np.sort(-x)

def sort_flip(x):
    return np.flip(np.sort(x)) 

arr=np.random.randint(1,10000,size=(1,100000))

%timeit sort_reverse(arr)
%timeit sort_negative(arr)
%timeit sort_flip(arr)

and the results are:

6.61 ms ± 67.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
6.69 ms ± 64.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
6.57 ms ± 58.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

3 Comments

Good to benchmark performance, thanks for your answer. I think this is the best, as this helps you choosing an approach. How does @Mazdak's answer do in this benchmark? Would be good to add .argsort as well
It is definitely slower (I tested it). However, I don't have my old machine to get the same values and compare them with the argsort method. On the other hand, these methods are more or less at the same speed, and the difference is noticeable if an extra large array is used. I myself use the standard python reversing method [::1] in my daily use if I deal with small arrays.
The statement “It seems np.flip() is slightly faster” isn’t entirely accurate based on the provided statistics. Considering the standard deviations, the differences are not statistically significant.
14

Be careful with dimensions.

Let

x  # initial numpy array
I = np.argsort(x) or I = x.argsort() 
y = np.sort(x)    or y = x.sort()
z  # reverse sorted array

Full Reverse

z = x[I[::-1]]
z = -np.sort(-x)
z = np.flip(y)
  • flip changed in 1.15, previous versions 1.14 required axis. Solution: pip install --upgrade numpy.

First Dimension Reversed

z = y[::-1]
z = np.flipud(y)
z = np.flip(y, axis=0)

Second Dimension Reversed

z = y[::-1, :]
z = np.fliplr(y)
z = np.flip(y, axis=1)

Testing

Testing on a 100×10×10 array 1000 times.

Method       | Time (ms)
-------------+----------
y[::-1]      | 0.126659  # only in first dimension
-np.sort(-x) | 0.133152
np.flip(y)   | 0.121711
x[I[::-1]]   | 4.611778

x.sort()     | 0.024961
x.argsort()  | 0.041830
np.flip(x)   | 0.002026

This is mainly due to reindexing rather than argsort.

# Timing code
import time
import numpy as np


def timeit(fun, xs):
    t = time.time()
    for i in range(len(xs)):  # inline and map gave much worse results for x[-I], 5*t
        fun(xs[i])
    t = time.time() - t
    print(np.round(t,6))

I, N = 1000, (100, 10, 10)
xs = np.random.rand(I,*N)
timeit(lambda x: np.sort(x)[::-1], xs)
timeit(lambda x: -np.sort(-x), xs)
timeit(lambda x: np.flip(x.sort()), xs)
timeit(lambda x: x[x.argsort()[::-1]], xs)
timeit(lambda x: x.sort(), xs)
timeit(lambda x: x.argsort(), xs)
timeit(lambda x: np.flip(x), xs)

2 Comments

np.flip() - super
I = np.argsort(x) and then z = x[-I] does not work when you have a zero in your x. By natural ordering it should go last, but it will go first in z since -0 == 0
10

Hello I was searching for a solution to reverse sorting a two dimensional numpy array, and I couldn't find anything that worked, but I think I have stumbled on a solution which I am uploading just in case anyone is in the same boat.

x=np.sort(array)
y=np.fliplr(x)

np.sort sorts ascending which is not what you want, but the command fliplr flips the rows left to right! Seems to work!

Hope it helps you out!

I guess it's similar to the suggest about -np.sort(-a) above but I was put off going for that by comment that it doesn't always work. Perhaps my solution won't always work either however I have tested it with a few arrays and seems to be OK.

Comments

8

Unfortunately when you have a complex array, only np.sort(temp)[::-1] works properly. The two other methods mentioned here are not effective.

3 Comments

@anishtain4: By "complex array", did you mean an array of complex numbers? Or did you mean an array with some other kind of complexity (if so pls specify what sort of complexity). In either case, I feel you could elaborate some more on your answer, by getting into how the other methods might fail. Thanks.
@fountainhead I mean the array of complex numbers. Since it's an old question I don't remember my test case from then to elaborate more.
@anishtain4 how do you even sort complex numbers? You cannot define ordering relations between complex numbers... you can only separately compare their real and imaginary parts, or their magnitudes.
2

You could sort the array first (Ascending by default) and then apply np.flip() (https://docs.scipy.org/doc/numpy/reference/generated/numpy.flip.html)

FYI It works with datetime objects as well.

Example:

    x = np.array([2,3,1,0]) 
    x_sort_asc=np.sort(x) 
    print(x_sort_asc)

    >>> array([0, 1, 2, 3])

    x_sort_desc=np.flip(x_sort_asc) 
    print(x_sort_desc)

    >>> array([3,2,1,0])

1 Comment

For those who have NaN in their arrays be careful, various proposed methods produce different results. For example if x = np.array([2,3,np.nan,1,0]) then the np.flip(np.sort(x)) approach yields [nan 3. 2. 1. 0.], while the -np.sort(-x) approach yields [ 3. 2. 1. 0. nan].
2

You can use the sort function from numpy :

array = np.random.rand(10) 
rev_sort = -np.sort(-array)

Comments

1

Here is a quick trick

In[3]: import numpy as np
In[4]: temp = np.random.randint(1,10, 10)
In[5]: temp
Out[5]: array([5, 4, 2, 9, 2, 3, 4, 7, 5, 8])

In[6]: sorted = np.sort(temp)
In[7]: rsorted = list(reversed(sorted))
In[8]: sorted
Out[8]: array([2, 2, 3, 4, 4, 5, 5, 7, 8, 9])

In[9]: rsorted
Out[9]: [9, 8, 7, 5, 5, 4, 4, 3, 2, 2]

Comments

0

Adding my 2 cents to the wonderful answer posted by @Mike O'Connor the below code is just another adaptation of the same using the bitwise inverse.

A = np.array([1, 2, 23, 4, 15, 78, 6, 7, 18, 9, 10]) 
~np.sort(~A)

Output: [78 23 18 15 10 9 7 6 4 2 1]

Comments

-3

i suggest using this ...

np.arange(start_index, end_index, intervals)[::-1]

for example:

np.arange(10, 20, 0.5)
np.arange(10, 20, 0.5)[::-1]

Then your resault:

[ 19.5,  19. ,  18.5,  18. ,  17.5,  17. ,  16.5,  16. ,  15.5,
    15. ,  14.5,  14. ,  13.5,  13. ,  12.5,  12. ,  11.5,  11. ,
    10.5,  10. ]

1 Comment

How does this solve the problem? You're just creating a completely, unrelated, new (descending) array which - by the way - could be done in a more efficient way: np.arange(20-0.5, 10-0.5, -0.5). But that's a different story and may be, because of the worse readability, debatable. An input array is not sorted at all

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.