218

If I want the maximum value in a list, I can just write max(List), but what if I also need the index of the maximum value?

I can write something like this:

maximum=0
for i,value in enumerate(List):
    if value>maximum:
        maximum=value
        index=i

But it looks tedious to me.

And if I write:

List.index(max(List))

Then it will iterate the list twice.

Is there a better way?

5
  • What do you mean by "it will pass list two times"? List.index(max(List)) works for me. Commented May 31, 2011 at 21:03
  • 18
    @mwc: It will iterate the list once to determine the maximum value, then iterate it a second time to find the index of that value. Commented May 31, 2011 at 21:04
  • 10
    Wouldn't list.index() be problematic if there are duplicated max values? Commented Feb 5, 2014 at 0:14
  • @LoganYang yes there could be two items with same value. Commented Jun 28, 2017 at 11:16
  • If the order is not important, you could do something like List.sort()[-1] Commented Jun 28, 2017 at 11:17

11 Answers 11

387

I think the accepted answer is great, but why don't you do it explicitly? I feel more people would understand your code, and that is in agreement with PEP 8:

max_value = max(my_list)
max_index = my_list.index(max_value)

This method is also about three times faster than the accepted answer:

import random
from datetime import datetime
import operator

def explicit(l):
    max_val = max(l)
    max_idx = l.index(max_val)
    return max_idx, max_val

def implicit(l):
    max_idx, max_val = max(enumerate(l), key=operator.itemgetter(1))
    return max_idx, max_val

if __name__ == "__main__":
    from timeit import Timer
    t = Timer("explicit(l)", "from __main__ import explicit, implicit; "
          "import random; import operator;"
          "l = [random.random() for _ in xrange(100)]")
    print "Explicit: %.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

    t = Timer("implicit(l)", "from __main__ import explicit, implicit; "
          "import random; import operator;"
          "l = [random.random() for _ in xrange(100)]")
    print "Implicit: %.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

Results as they run in my computer:

Explicit: 8.07 usec/pass
Implicit: 22.86 usec/pass

Other set:

Explicit: 6.80 usec/pass
Implicit: 19.01 usec/pass
Sign up to request clarification or add additional context in comments.

6 Comments

Didn't expect it to be faster. It is faster even when I replace l with "l = [random.random() for _ in xrange(10000000)]+[2]", which guarantees that last element is the largest.
@Sunny88: For a simple list of numbers, the simple approach is faster. If you are after performance in this case, I'd suggest to use numpy.argmax(), which is another 30 times faster on my machine. If the list contains more complicated objects than mere numbers, the approach in my answer can become faster. Wnother advantage of that approach is that it can be used for arbitrary iterators, not only for lists.
@Sven-Marnach Would numpy be faster, if I had to convert my list to a numpy array first? Would it be faster for the simple example [0,1,0]?
@Sven-Marnach I just checked. numpy.argmax is by far the slowest method, and it gives the wrong answer, if the array contains strings instead of floats or integers.
Wouldn't list.index() be problematic if there are duplicated max values?
|
213

There are many options, for example:

import operator
index, value = max(enumerate(my_list), key=operator.itemgetter(1))

4 Comments

Ah, I have seen this in other places, but I thought that it will return just one value, not a tuple.
@Sunny88: The key function is only used to decide which element is maximal. The elements are not changed.
@SvenMarnach Why not key=lambda e: e[1] instead and thereby avoid the import?
@lifebalance Using itemgetter() is faster, and avoiding an import isn't a goal worth pursuing. Avoiding external dependencies can be worthwhile in some cases, but an import from the standard library is a non-issue.
23

This answer is 33 times faster than @Escualo assuming that the list is very large, and assuming that it's already an np.array(). I had to turn down the number of test runs because the test is looking at 10000000 elements not just 100.

import random
from datetime import datetime
import operator
import numpy as np

def explicit(l):
    max_val = max(l)
    max_idx = l.index(max_val)
    return max_idx, max_val

def implicit(l):
    max_idx, max_val = max(enumerate(l), key=operator.itemgetter(1))
    return max_idx, max_val

def npmax(l):
    max_idx = np.argmax(l)
    max_val = l[max_idx]
    return (max_idx, max_val)

if __name__ == "__main__":
    from timeit import Timer

t = Timer("npmax(l)", "from __main__ import explicit, implicit, npmax; "
      "import random; import operator; import numpy as np;"
      "l = np.array([random.random() for _ in xrange(10000000)])")
print "Npmax: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

t = Timer("explicit(l)", "from __main__ import explicit, implicit; "
      "import random; import operator;"
      "l = [random.random() for _ in xrange(10000000)]")
print "Explicit: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

t = Timer("implicit(l)", "from __main__ import explicit, implicit; "
      "import random; import operator;"
      "l = [random.random() for _ in xrange(10000000)]")
print "Implicit: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

Results on my computer:

Npmax: 8.78 msec/pass
Explicit: 290.01 msec/pass
Implicit: 790.27 msec/pass

5 Comments

Just to clarify: the speedup is just due to the numpy C implementation versus pure python? Or there's a way to get any improvement to @Escualo's answer using pure python?
If one would like to use python 3.6 one can do something like: "l = np.array([random.random() for _ in range(10000000)])") print (f"Npmax: {(1000 * t.timeit(number=10)/10 ):5.2f} msec/pass ")
This was on 2.7
Well, the speed of numpy.argmax looks amazing until you let it process a standard python list. Then the speed lies between explicit and implicit version. I guess np.array does not just create a list but it saves some extra info in it - like for example min and max values (just a hypothesis).
@MiroslawOpoka I have tried to briefly check the source code and did not find any such "pre computed aggregates" (though I'm not sure at all since the code is not so simple, and many more general storage systems such as databases/storage formats do indeed record such min/max aggregates). Just the memory layout of numpy, plus the C compilation could account for a drastic speedup, though.
21

With Python's built-in library, it's pretty easy:

a = [2, 9, -10, 5, 18, 9] 
max(xrange(len(a)), key = lambda x: a[x])

This tells max to find the largest number in the list [0, 1, 2, ..., len(a)], using the custom function lambda x: a[x], which says that 0 is actually 2, 1 is actually 9, etc.

1 Comment

In Python 3, there is no xrange , if you want to write code that will run for both Python 2 and Python 3, you should use range().
18

I would suggest a very simple way:

import numpy as np
l = [10, 22, 8, 8, 11]
print(np.argmax(l))
print(np.argmin(l))

Hope it helps.

Comments

12

This converts my_list to a list of tuples (v,i) where v is every item of my list and i is the correspondent index, then it gets the tuple with the maximun value and with its associated index too:

max([(v,i) for i,v in enumerate(my_list)])

5 Comments

This is better because you can adapt it to use with something other than tuple.
How exactly does this work? Can you break down the process?
Hi @clabe45, it converts my_list in a list of tuples (v,i) where v is every item of my list and i is the correspondent index, then it gets the tuple with the maximun value (and with its associated index too)
Thanks, can you post that in the answer possibly? And how does max know to just take the first item of every tuple (v) into account when calculating the maximum value?
@clabe45 May be this reply comes too late, but for others (like me) who came across this thread now, here: stackoverflow.com/questions/18296755/… is an explanation. Not this line: "By default max will will compare the items by the first index, if the first index is same then it'd compare the second index." So I gave it a try with list: l=[1,1,1] and then max([(v,i) for i,v in enumerate(l)]) and it gives me not the first 1 but the last one: (1,2) as result. I hope it explains :)
5
max([(value,index) for index,value in enumerate(your_list)]) #if maximum value is present more than once in your list then this will return index of the last occurrence

If maximum value in present more than once and you want to get all indices,

max_value = max(your_list)
maxIndexList = [index for index,value in enumerate(your_list) if value==max(your_list)]

Comments

2

Maybe you need a sorted list anyway?

Try this:

your_list = [13, 352, 2553, 0.5, 89, 0.4]
sorted_list = sorted(your_list)
index_of_higher_value = your_list.index(sorted_list[-1])

1 Comment

1. Sorting has higher time complexity. 2. sorted_list hasn't indexes but values, so it would not work.
0

I made some big lists. One is a list and one is a numpy array.

import numpy as np
import random
arrayv=np.random.randint(0,10,(100000000,1))
listv=[]
for i in range(0,100000000):
    listv.append(random.randint(0,9))

Using jupyter notebook's %%time function I can compare the speed of various things.

2 seconds:

%%time
listv.index(max(listv))

54.6 seconds:

%%time
listv.index(max(arrayv))

6.71 seconds:

%%time
np.argmax(listv)

103 ms:

%%time
np.argmax(arrayv)

numpy's arrays are crazy fast.

Comments

0

List comprehension method:

Let's say you have some list List = [5,2,3,8]

Then [i for i in range(len(List)) if List[i] == max(List)] would be a pythonic list comprehension method to find the values "i" where List[i] == max(List).

It is easily scalable for arrays that are lists of lists, simply by doing a for loop.

For instance, with an arbitrary list of lists "array" and initalizing "index" as an empty list.

array = [[5, 0, 1, 1], 
[1, 0, 1, 5], 
[0, 1, 6, 0], 
[0, 4, 3, 0], 
[5, 2, 0, 0], 
[5, 0, 1, 1], 
[0, 6, 0, 1], 
[0, 1, 0, 6]]
index = []

for List in array:
    index.append([i for i in range(len(List)) if List[i] == max(List)])
index

Output: [[0], [3], [2], [1], [0], [0], [1], [3]]

Comments

-1

Here is a complete solution to your question using Python's built-in functions:

# Create the List
numbers = input("Enter the elements of the list. Separate each value with a comma. Do not put a comma at the end.\n").split(",") 

# Convert the elements in the list (treated as strings) to integers
numberL = [int(element) for element in numbers] 

# Loop through the list with a for-loop

for elements in numberL:
    maxEle = max(numberL)
    indexMax = numberL.index(maxEle)

print(maxEle)
print(indexMax)

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.