Reputation: 8090
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])
.
Upvotes: 0
Views: 95
Reputation: 36765
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
b[x]
was larger than all elements in a
, orb[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.
Upvotes: 3
Reputation: 510
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.
Upvotes: 0
Reputation: 12015
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]
Upvotes: 0
Reputation: 4528
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]
Upvotes: 0