0

How can I get the last index of the element in a where b > a when a and b have different length using numpy.

For instance, for the following values:

>>> a = np.asarray([10, 20, 30, 40])
>>> b = np.asarray([12, 25])

I would expect a result of [0, 1] (0.. because 12 > 10 -> index 0 in a; 1.. because 25 > 20 -> index 1 in a). Obviously, the length of the result vector should equal the length of b (and the values of the result list should be less than the length of a (as they refer to the indices in a)).

Another test is for b = np.asarray([12, 25, 31, 9, 99]) (same a as above), the result should be array([ 0, 1, 2, -1, 3]).

2
  • 1
    Shouldn't the result be [0, 0] because 25 > 10? Commented Jun 28, 2018 at 6:16
  • @Kasramvd: You're right. I didn't describe this properly. Let me rectify the question... Commented Jun 28, 2018 at 6:35

4 Answers 4

3

A vectorized solution:

Remember that you can compare all elements in b with all elements in a using broadcasting:

b[:, None] > a
# array([[ True, False, False, False],     # b[0] > a[:]
#        [ True,  True, False, False]])    # b[1] > a[:]

And now find the index of the last True value in each row, which equals to the first False value in each row, minus 1

np.argmin((b[:, None] > a), axis=1) - 1
# array([0, 1])

Note that there might be an ambiguity as to what a returned value of -1 means. It could mean

  1. b[x] was larger than all elements in a, or
  2. b[x] was not larger than any element in a

In our data, this means

a = np.asarray([10, 20, 30, 40])
b = np.asarray([9, 12, 25, 39, 40, 41, 50])

mask = b[:, None] > a
# array([[False, False, False, False],   # 9 is smaller than a[:], case 2
#        [ True, False, False, False],
#        [ True, False, False, False],
#        [ True,  True,  True, False],
#        [ True,  True,  True, False],
#        [ True,  True,  True,  True],   # 41 is larger than a[:], case 1
#        [ True,  True,  True,  True]])  # 50 is larger than a[:], case 1

So for case 1 we need to find rows with all True values:

is_max = np.all(mask, axis=1)

And for case 2 we need to find rows with all False values:

none_found = np.all(~mask, axis=1)

This means we can use the is_max to find and replace all case 1 -1 values with a positive index

mask = b[:, None] > a
is_max = np.all(mask, axis=1)
# array([False, False, False, False, False,  True,  True])
idx = np.argmin(mask, axis=1) - 1
# array([-1,  0,  0,  2,  2, -1, -1])
idx[is_max] = len(a) - 1
# array([-1,  0,  0,  2,  2,  3,  3])

However be aware that the index -1 has a meaning: Just like 3 it already means "the last element". So if you want to use idx for indexing, keeping -1 as an invalid value marker may cause trouble down the line.

Sign up to request clarification or add additional context in comments.

6 Comments

Awesome ;-)! Thanks.
Any idea how I can handle inputs (b) that are smaller than all values in a, i.e. for which there is no index? For b = np.asarray([12, 25, 31, 9]) the result is array([0, 1, 2, 3]) which is the same as if the last value in b (9) was > 40.
Your last edit provided what I need. The index is now -1 which isn't ambiguous any more.
the index -1 is "the last index". Maybe you should mark too small elements differently
I have added some explanation what -1 means, and a way of detecting what condition caused a -1 to be returned.
|
0

Works even a has shorter length than b , first choose shorter list length then check if its has smaller numbers element wise :

[i for i in range(min(len(a),len(b))) if min(a, b, key=len)[i] > max(a, b, key=len)[i]]
# [0, 1]

Comments

0

You can zip a and b to combine them and then enumerate to iterate it with its index

[i for i,(x,y) in enumerate(zip(a,b)) if y>x]
# [0, 1]

Comments

0
np.asarray([i for i in range(len(b)) if b[i]>a[i]])

This should give you the answer. Also the length does not have to be same as that of either a or b.

Comments

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.