82

I have a list say a = [5,3,1,4,10]. I need to get indices of the top two values of the list, that is for 5 and 10 I would get [0, 4]. Is there a one-liner that Python offers for such a case?

Georgy
  • 12,464
  • 7
  • 65
  • 73
hardikudeshi
  • 1,441
  • 5
  • 18
  • 22
  • When you say 'values', do you only mean ints? floats? numeric? string? arbitrary object? It's better to give an example list that tests mixed types. – smci May 25 '23 at 21:45

3 Answers3

134
sorted(range(len(a)), key=lambda i: a[i])[-2:]

or

sorted(range(len(a)), key=lambda i: a[i], reverse=True)[:2]

or

import operator

zip(*sorted(enumerate(a), key=operator.itemgetter(1)))[0][-2:]

or (for long lists), consider using heapq.nlargest

zip(*heapq.nlargest(2, enumerate(a), key=operator.itemgetter(1)))[0]
David Beauchemin
  • 231
  • 1
  • 2
  • 12
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • 1
    In Python 3, zip returns an iterable object. So, the last one would have slight modification: `list(zip(...))[0]` – Joseph Apr 23 '20 at 04:00
34

Just a NumPy alternative:

import numpy as np

top_2_idx = np.argsort(a)[-2:]
top_2_values = [a[i] for i in top_2_idx]
Georgy
  • 12,464
  • 7
  • 65
  • 73
aikramer2
  • 1,283
  • 12
  • 9
  • 6
    If you're willing to use `numpy`, it's more efficient to use `argpartition` than `argsort`. See this answer: https://stackoverflow.com/a/23734295/388951 – danvk Aug 02 '18 at 15:49
1

As danvk suggested, we can use argpartion method of numpy for good efficiency like this answer.

If we need two top indexes, we can use this sample code:

import numpy as np
# Find two top indexes
ind = np.argpartition(a, -2)[-2:]
# Sort them
ind = ind[np.argsort(a[ind])]
Alireza Mazochi
  • 897
  • 1
  • 15
  • 22