Вариант 1
numpy.unique
Эта опция быстра, но она будет возвращать индекс первого первого экземпляра для каждого дубликата, в то время как в вашем вопросе вы получаете индекс 1011 * last дубликата. Это означает, что индексы, возвращаемые этим методом, не будут соответствовать желаемому результату, но значения, которым они соответствуют, будут идентичны.
vals, indices = np.unique(example[mask], return_index=True)
indices + np.argmax(mask)
array([199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 220, 221,
222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234,
235, 236, 237, 238, 239], dtype=int64)
А вот оговорка, о которой я упоминал:
desired = np.array([199, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234,
235, 236, 237, 238, 239])
np.array_equal(start + idx, desired)
# False
np.array_equal(example[start + idx], example[desired])
# True
Вариант 2
numpy.unique
+ numpy.flip
f = np.flip(example[mask])
vals, indices = np.unique(f, return_index=True)
final = f.shape[0] - 1 - indices
final + np.argmax(mask)
array([199, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234,
235, 236, 237, 238, 239], dtype=int64)
Это фактически захватывает последний случай, но добавляет дополнительные накладные расходы:
np.array_equal(final + idx[0], desired)
# True
Производительность (я включил некоторые расходы на настройку)
def chris1(arr, mn, mx):
mask = (arr < mx) & (arr > mn)
vals, indices = np.unique(arr[mask], return_index=True)
return indices + np.argmax(mask)
def chris2(arr, mn, mx):
mask = (arr < mx) & (arr > mn)
f = np.flip(arr[mask])
vals, indices = np.unique(f, return_index=True)
final = f.shape[0] - 1 - indices
return final + np.argmax(mask)
def sbfrf(arr, mn, mx):
mask = (arr < mx) & (arr > mn)
idx = np.argwhere(mask).squeeze()
if len(set(example[idx])) != len(example[idx]):
dupes = np.array([x for n, x in enumerate(example[idx]) if x in example[idx][:n]]).squeeze()
idx = np.delete(idx, np.nonzero(np.in1d(example[idx], dupes).squeeze()[::2]))
return idx
In [225]: %timeit chris1(example, 198_000, 230_000)
29.6 µs ± 133 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [226]: %timeit chris2(example, 198_000, 230_000)
36.5 µs ± 98.6 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [227]: %timeit sbfrf(example, 198_000, 230_000)
463 µs ± 7.77 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)