在列表中找到最大值及其索引的Pythonic方法?


151

如果我想要列表中的最大值,我可以只写max(List),但是如果我还需要最大值的索引怎么办?

我可以这样写:

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

但这对我来说很乏味。

如果我写:

List.index(max(List))

然后它将迭代列表两次。

有没有更好的办法?


您将“两次通过列表”是什么意思?List.index(max(List))为我工作。
mwcz

14
@mwc:它将对列表进行一次迭代以确定最大值,然后再次对其进行迭代以找到该值的索引。

10
如果存在重复的最大值,list.index()不会有问题吗?
Logan Yang

@LoganYang是的,可能有两个具有相同值的项目。
Florian

如果顺序不重要,则可以执行List.sort()[-1]
Florian

Answers:


186

有很多选项,例如:

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

2
嗯,我在其他地方也看到了这一点,但我认为它只会返回一个值,而不是元组。
2011年

1
@ Sunny88:该key函数仅用于确定哪个元素最大。元素未更改。
Sven Marnach

6
@SvenMarnach为什么不改key=lambda e: e[1]而避免导入?
生命平衡'17

8
@lifebalance使用起来itemgetter()更快,避免导入不是一个值得追求的目标。在某些情况下,避免外部依赖可能是值得的,但是从标准库中导入则不是问题。
Sven Marnach '17

323

我认为公认的答案很好,但是为什么不明确地做呢?我感觉更多的人会理解您的代码,这与PEP 8一致:

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

此方法也比接受的答案快三倍:

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)

结果在我的计算机上运行:

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

其他套装:

Explicit: 6.80 usec/pass
Implicit: 19.01 usec/pass

3
没想到它会更快。即使将l替换为“ l = [xrange(10000000)中的_的_ [random.random()] + [2]”,这也保证了最后一个元素最大。
2011年

14
@ Sunny88:对于简单的数字列表,简单的方法更快。如果在这种情况下您追求性能,我建议使用numpy.argmax(),这在我的计算机上要快30倍。如果列表中包含的对象比单纯的数字复杂得多,我的答案就会变得更快。这种方法的另一个优点是,它不仅可以用于列表,还可以用于任意迭代器。
Sven Marnach 2011年

@ Sven-Marnach如果必须先将列表转换为numpy数组,numpy会更快吗?简单的例子[0,1,0]会更快吗?
tommy.carstensen

1
我刚刚检查了@ Sven-Marnach。numpy.argmax是迄今为止最慢的方法,如果数组包含字符串而不是浮点数或整数,则它给出错误的答案。
tommy.carstensen

9
如果存在重复的最大值,list.index()不会有问题吗?
Logan Yang

20

假设列表很大,并且假设它已经是np.array(),那么这个答案比@Escualo快33倍。我不得不拒绝测试运行的次数,因为该测试所关注的是10000000个元素,而不仅仅是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 )

我计算机上的结果:

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

只是要澄清一下:加速仅仅是由于numpy C实现与纯python?或者有一种方法可以使用纯python来改善@Escualo的答案?
最高

如果要使用python 3.6,可以执行以下操作:“ l = np.array([_在range(10000000)中的_ [random.random()for _]]”)print(f“ Npmax:{(1000 * t。 timeit(number = 10)/ 10):5.2f} msec / pass“)
Piotr Siejda

这是2.7
portforwardpodcast

1
好吧,numpy.argmax除非您让它处理标准的 python列表,否则看起来的速度惊人。然后,速度介于显式和隐式版本之间。我想np.array不仅会创建一个列表,还会在其中保存一些额外的信息-例如最小值和最大值(只是一个假设)。
Miroslaw Opoka '19

17

使用Python的内置库,非常简单:

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

这告诉max[0, 1, 2, ..., len(a)]使用自定义函数查找列表中最大的数字,该函数lambda x: a[x]表示0is 21is 9等等。


在Python 3中,没有xrange,如果要编写将同时在Python 2和Python 3上运行的代码,则应使用range()。
黄春德

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

这样比较好,因为您可以使其适应除元组以外的其他东西使用。
wieczorek1990

这是如何工作的?你能分解这个过程吗?
clabe45

@ clabe45,您好,它将my_list转换为元组(v,i)的列表,其中v是列表中的每一项,而i是对应的索引,然后它获得具有maximun值(以及相关索引)的元组
Luis Sobrecueva

4
谢谢,您可以将其张贴在答案中吗?怎么max知道v在计算最大值时只考虑每个元组()的第一项?
clabe45

1
@ clabe45可能是这个答复来得太迟,但是对于现在遇到此线程的其他人(如我),请访问:stackoverflow.com/questions/18296755/…是一种解释。不是这一行:“默认情况下,max将按第一个索引比较项目,如果第一个索引相同,则将比较第二个索引。” 所以我尝试了一个列表:l = [1,1,1]然后是max([(v,i)for enumerate(l)中的i,v]),它不是第一个,而是最后一个一:(1,2)作为结果。我希望它能解释:)
Anupam Jain


4
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

如果当前的最大值不止一次并且您想要获取所有索引,

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

1
对。我几乎贴出了一个答案,但是后来我看到您已经在列表理解单行代码中使用了相同的逻辑解决方案。
WalyKu

2

也许您仍然需要一个排序列表?

试试这个:

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.排序具有较高的时间复杂度。2. sorted_list没有索引,但是有值,所以它不起作用。

1

很抱歉恢复了该线程,但认为我的方法值得添加。

此示例中的列表名称为“列表”

list.sort()
print(list[-1])

这将轻松打印列表中的最高值!

list.sort()ASCII表中项目的值对列表进行排序,因此有效地对列表进行从低到高的排序。然后,我只需使用即可打印列表中的最后一个值(这将是最大的数字)print(list[-1])

希望这可以帮助!


5
我们无法以这种方式获取索引
toing_toing

-1

这是使用Python的内置函数为您的问题提供的完整解决方案:

# 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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.