3

There is a number of questions out here concerning sorting arrays but I was not able to find the one solving my problem (which makes me hope that I'm not thinking way to complicated). So here we go:

I have two arrays with equal values but in different order:

a = np.array([4, 2, 5, 6])
# b = np.random.permutation(a)  # general case
b = np.array([5, 2, 6, 4])

I need the indices that sort b to a, so here:

ind = np.array([3, 1, 0, 2])

Note that I do not want to change a.

2
  • 1
    in this case, a is sorted ... is always true? Commented May 4, 2015 at 17:29
  • Sorry, I tried to make the example as easy as possible and actually made it too easy... Interchanged 2 and 4 in a Commented May 4, 2015 at 17:40

3 Answers 3

4

One approach with broadcasting & np.where -

_,C = np.where(a[:,None] == b)

Sample run -

In [210]: a = np.array([4, 2, 5, 6])

In [211]: b = np.array([5, 2, 6, 4])

In [212]: _,C = np.where(a[:,None] == b)

In [213]: C
Out[213]: array([3, 1, 0, 2], dtype=int64)
Sign up to request clarification or add additional context in comments.

1 Comment

Note that if a and b are large, this builds a boolean array of len(a) x len(b) which might be excessive depending on the use-case.
3

np.argsort is its own inverse. If y = x[x.argsort()], then x = y[x.argsort().argsort()]. Specifically, you convert a into a sorted array with a.argsort(), and convert from a sorted array to b with b.argsort().argsort(). You can therefore write:

b = a[a.argsort()][b.argsort().argsort()]

In other words:

ind = a.argsort()[b.argsort().argsort()]

4 Comments

The first code snippet should be b = a[a.argsort()[b.argsort().argsort()]] (note the closing bracket) as is clear from the second snippet.
@StenL. I'm pretty sure the two are equivalent based on my understanding of how indices work. If you have a counter-example, I'd be happy to shatter my world-view
Ah, you're right. Still, for anyone stumbling on this in the future, this is the correct answer and the one currently marked correct is incorrect.
This is very useful, especially in the case of very large arrays for which other options are much more computationally expensive
2

In this case, a is already sorted. So, all you need are the sorting indices for b.

However, in case a was not sorted, you can do

a = array([2, 4, 5, 6])
b = array([5, 2, 6, 4])
b.argsort()[a.argsort()] # array([1, 3, 0, 2])

This uses the argsort method to return the indices needed to sort b and a.

Another example:

a = array([4, 2, 5, 6])
b = array([5, 2, 6, 4])
b.argsort()[a.argsort()] # array([3, 1, 0, 2])

3 Comments

this does not seem to work for arrays with non-unique elements: a = np.array([4, 4, 2, 5, 6]) and b = np.array([5, 2, 4, 6, 4]).
@leo. That's because there's a missing argsort.
This answer is incorrect. The correct answer is b = a[a.argsort()[b.argsort().argsort()]] as given by @MadPhysicist below (but correcting the misplaced bracket).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.