如何在列表中找到所有最大值的位置?

217
  • Item 1
  • Item 2
  • Item 3

  • 项目1
  • 项目2
  • 项目3
a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 55, 23, 31, 55, 21, 40, 18, 50,
             35, 41, 49, 37, 19, 40, 41, 31]

最大的元素为55(位置9和12上有两个元素)

我需要找出最大值位于哪些位置。请帮忙。

18个回答

377
a.index(max(a))

会告诉你列表 a 中最大值元素的第一次出现的索引。


19
然而,这只能获取到第一个实例,而他要求获取所有最大值被发现的索引。你需要使用切片在其中循环并获取每个情况下剩余的列表,并在不再找到最大值时处理异常。 - user483040
11
我曾提到它只会给出第一个实例。如果你想要所有的实例,SilentGhost的解决方案更加优美并且不容易出错。 - nmichaels
9
至少按照我的理解,这个问题明确要求在存在多个最大值的情况下列出列表... - emmagras
2
从技术上讲,你可以使用这个方法来获取最大值元素的第一个实例,然后将它设置为一个极大的负数,接着寻找下一个最大值,但那样会太复杂了。 - Neil
2
它明确地表示“全部”。请不要垃圾邮件,这里的目标是尽快帮助人们,而不是获得徽章和声望(如果您真的想帮助,请删除您的答案)。 - Wildhammer
显示剩余2条评论

260
>>> m = max(a)
>>> [i for i, j in enumerate(a) if j == m]
[9, 12]

5
如果您不介意多次通过列表,那么我的回答是:请提供更具体的上下文。 - martineau
除了大 0 的情况,这个列表的迭代次数是 2n,其中一次用于确定最大值,另一次用于查找最大值的位置。对于非常长的列表,跟踪当前最大值及其位置的 for 循环可能更有效。 - radtek
9
大O表示法只是n,大O中忽略了前导系数。 - michaelsnowden
4
从理论上讲,O(N)和O(2N)是相同的,但实际上,特别是当N趋近于无穷大时,O(N)肯定会有更短的运行时间。 - radtek

22
被选为答案的(和大多数其他答案)需要至少通过列表两次。
以下是一种单次遍历的解决方案,对于更长的列表可能是更好的选择。 编辑:为了解决@John Machin指出的两个不足之处。 对于(2),我尝试根据每个条件的出现概率的猜测和从前任中允许的推断来优化测试。 找到适当的初始化值以使max_valmax_indices在所有可能的情况下都能正常工作有些棘手,特别是如果最大值恰好是列表中的第一个值-但我相信现在已经可以了。
def maxelements(seq):
    ''' Return list of position(s) of largest element '''
    max_indices = []
    if seq:
        max_val = seq[0]
        for i,val in ((i,val) for i,val in enumerate(seq) if val >= max_val):
            if val == max_val:
                max_indices.append(i)
            else:
                max_val = val
                max_indices = [i]

    return max_indices

4
(1) 空列表的处理需要注意。应该返回承诺中的 [](“返回列表”)。代码应该简单地写成 if not seq: return []。 (2) 循环中的测试方案不够优化:在随机列表中,条件 val < maxval 通常是最常见的,但上述代码却需要进行两次测试而不是一次。 - John Machin
对于@John Machin的评论给予+1,因为他捕捉到了文档字符串的不一致性,并且没有让我逃脱发布次优代码的惩罚。说实话,既然已经有一个答案被接受了,我失去了继续工作的动力,因为我认为几乎没有人会再看它——而且它比其他人的答案都长得多。 - martineau
1
@martineau:“被接受”的答案不一定是“可接受的”。我通常会阅读所有的答案,包括您的修订版。现在它进行了3个测试,而不是2个,以防万一出现==的情况 - 您的elif条件将始终为真。 - John Machin
@John Machin:我非常受启发,进一步修订了它。现在仅需进行最少额外的测试,再加上一些其他微调即可。感谢您的评论和建设性的批评。顺带一提,我自己也注意到了始终为 True 的 elif。;-) - martineau
@John Machin:嗯,你的时间结果似乎与我的相矛盾,所以我将删除我在答案中关于时间的说法,以便我可以进一步了解情况。感谢你提醒我。实际上,我认为“真正”的计时测试需要使用随机列表值。 - martineau
显示剩余2条评论

19
我想到了以下代码,可以像您在列表上使用max、min和其他函数一样正常运行:
请考虑下面这个例子列表,找出列表a中最大值的位置:
>>> a = [3,2,1, 4,5]

使用生成器enumerate并进行强制转换

>>> list(enumerate(a))
[(0, 3), (1, 2), (2, 1), (3, 4), (4, 5)]

此时,我们可以使用max的位置

>>> max(enumerate(a), key=(lambda x: x[1]))
(4, 5)

以上告诉我们,最大值位于位置4,其值为5。

正如您所看到的,在key参数中,您可以通过定义适当的lambda函数找到任何可迭代对象上的最大值。

希望这有所帮助。

附注:正如@PaulOyster在评论中指出的那样。 在Python 3.x中,minmax允许一个新的关键字default,它可以避免在参数为空列表时引发ValueError异常。 max(enumerate(list), key=(lambda x:x[1]), default = -1)


4
这是一个更好的解决方案,因为它只需要一次遍历。虽然有几点需要注意:1.不需要将枚举转换为列表,2.lambda最好加上括号,3.min()和max()现在具有默认参数(在空输入时返回),所以可以使用它(例如default=-1)来避免ValueError异常,4.请更改为max(),因为这是原始问题。 - Paul Oyster
关于编程的内容,翻译成中文如下:大约有3项,是的,它只适用于Python 3.x。我会提到这点。并且修复了其他所有问题。 ;) - Jonathan Prieto-Cubides
5
当列表中的最大值元素出现多次时,这只会找到其中一个最大值元素(第一个),因此无法回答所提出的问题。 - martineau
这个解决方案与 OP 所要求的略有不同,但如果我们只想在一次遍历中找到最大索引,这似乎是一个更好的方法。我建议将 default = (None, None) 设为默认值,以便在像 max_index,max_value = max(enumerate(list),key=(lambda x:x[1]),default = (None, None)) 这样分配给某些变量时符合返回类型。 - rainversion_3

13

还有一种方法可以只找到第一次出现的解决方案,这可以通过使用numpy来实现:

>>> import numpy as np
>>> a_np = np.array(a)
>>> np.argmax(a_np)
9

11

我无法复现@martineau引用的@SilentGhost超越性能。以下是我的测试结果:

=== maxelements.py ===

a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 55, 23, 31, 55, 21, 40, 18, 50,
             35, 41, 49, 37, 19, 40, 41, 31]
b = range(10000)
c = range(10000 - 1, -1, -1)
d = b + c

def maxelements_s(seq): # @SilentGhost
    ''' Return list of position(s) of largest element '''
    m = max(seq)
    return [i for i, j in enumerate(seq) if j == m]

def maxelements_m(seq): # @martineau
    ''' Return list of position(s) of largest element '''
    max_indices = []
    if len(seq):
        max_val = seq[0]
        for i, val in ((i, val) for i, val in enumerate(seq) if val >= max_val):
            if val == max_val:
                max_indices.append(i)
            else:
                max_val = val
                max_indices = [i]
    return max_indices

def maxelements_j(seq): # @John Machin
    ''' Return list of position(s) of largest element '''
    if not seq: return []
    max_val = seq[0] if seq[0] >= seq[-1] else seq[-1]
    max_indices = []
    for i, val in enumerate(seq):
        if val < max_val: continue
        if val == max_val:
            max_indices.append(i)
        else:
            max_val = val
            max_indices = [i]
    return max_indices

以下是在一台老旧的笔记本电脑上运行Python 2.7和Windows XP SP3系统得出的结果:

>\python27\python -mtimeit -s"import maxelements as me" "me.maxelements_s(me.a)"
100000 loops, best of 3: 6.88 usec per loop

>\python27\python -mtimeit -s"import maxelements as me" "me.maxelements_m(me.a)"
100000 loops, best of 3: 11.1 usec per loop

>\python27\python -mtimeit -s"import maxelements as me" "me.maxelements_j(me.a)"
100000 loops, best of 3: 8.51 usec per loop

>\python27\python -mtimeit -s"import maxelements as me;a100=me.a*100" "me.maxelements_s(a100)"
1000 loops, best of 3: 535 usec per loop

>\python27\python -mtimeit -s"import maxelements as me;a100=me.a*100" "me.maxelements_m(a100)"
1000 loops, best of 3: 558 usec per loop

>\python27\python -mtimeit -s"import maxelements as me;a100=me.a*100" "me.maxelements_j(a100)"
1000 loops, best of 3: 489 usec per loop

10

您也可以使用numpy软件包:

import numpy as np
A = np.array(a)
maximum_indices = np.where(A==max(a))

这将返回一个包含最大值的所有索引的numpy数组

如果要将其转换为列表:

maximum_indices_list = maximum_indices.tolist()

7
a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 
         55, 23, 31, 55, 21, 40, 18, 50,
         35, 41, 49, 37, 19, 40, 41, 31]

import pandas as pd

pd.Series(a).idxmax()

9

这通常是我做事的方法。

6
>>> max(enumerate([1,2,3,32,1,5,7,9]),key=lambda x: x[1])
>>> (3, 32)

这是错误的。尝试将最大数放在列表中间。 - loopbackbee
1
这是错误的。问题要求“找到最大值的所有位置”。 - Kapil

5

@shash 在其他地方回答了这个问题

A Pythonic way to find the index of the maximum list element would be

position = max(enumerate(a), key=lambda x: x[1])[0]

这种方法只需要一次遍历 (one pass),但速度比@Silent_Ghost和@nmichaels的解决方案要慢。

for i in s m j n; do echo $i;  python -mtimeit -s"import maxelements as me" "me.maxelements_${i}(me.a)"; done
s
100000 loops, best of 3: 3.13 usec per loop
m
100000 loops, best of 3: 4.99 usec per loop
j
100000 loops, best of 3: 3.71 usec per loop
n
1000000 loops, best of 3: 1.31 usec per loop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接