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


152

我有一个清单:

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上的两个元素)

我需要找到最大值位于哪个位置。请帮忙。

Answers:


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

4
如果您不介意多次通过列表,这是一个很好的简短答案-这很可能。
martineau 2010年

除此的大0为2n之外,列表将迭代2x,一次确定最大值,另一次查找最大值的位置。对于真正的长列表,跟踪当前最大值及其位置的for循环可能更有效。
radtek

1
@radtek大O只是n。大O忽略了前导系数
michaelsnowden

1
理论上O(N)和O(2N)相同,但是实际上,O(N)的运行时间肯定会更短,尤其是当N接近无穷大时。
radtek

313
a.index(max(a))

会告诉您list的最大值元素的第一个实例的索引a


8
但是,这只会使您获得第一个实例,并且他询问了找到最大值的所有索引。您必须循环使用slice来获取每种情况下的剩余列表,并在找不到该异常时处理该异常。
jaydel

10
我确实提到过,它只会给初审。如果您想全部使用它们,SilentGhost的解决方案更漂亮,出错的可能性也更少。
nmichaels

7
至少在我谈到时,这个问题明确要求在有多个最大值的情况下列出一个清单...
emmagras,2015年

2
从技术上讲,您可以使用它来获取值最大的元素的第一个实例,然后将其设置为一个非常大的负数,然后找到值第二高的元素,但这太复杂了。
尼尔·乔杜里

@nmichaels除了接受的答案之外,还有什么最好的方法来获取列表中所有最大值的位置?
谢克(Shaik)

18

所选答案(以及大多数其他答案)需要至少两次通过列表。
这是一站式解决方案,对于较长的列表而言可能是更好的选择。

编辑:解决@John Machin指出的两个缺陷。对于(2),我尝试根据各种条件的估计发生概率和前辈的推论来优化测试。找出适当的初始化值max_valmax_indices在所有可能的情况下都可行,这有点棘手,特别是如果max恰好是列表中的第一个值-但我相信现在可以了。

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是最常见的,但是上面的代码进行了2次测试,而不是一次。
约翰·马钦

为@John Machin的评论+1,因为他们发现了与文档字符串不一致的地方,并且没有让我放弃发布次优的代码。实话说,既然答案已经被接受,我就失去了继续研究答案的动力,因为我认为几乎没有人会看它了,而且比任何人都更长。
martineau 2010年

1
@martineau:“接受”的答案不一定是“可接受的”。我通常会阅读所有答案。包括您的修订。现在在很少的情况下进行3次测试,==而不是2次-您的elif条件将始终为真。
约翰·马钦

@约翰·马钦(John Machin):我得到了很大的启发,并进行了进一步的修订。现在,它正在进行最低限度的附加测试,以及其他一些调整。感谢您的评论和建设性的批评。我抓到了永远都是True的elif自己,FWIW。;-)
martineau 2010年

@John Machin:嗯,您的计时结果似乎与我自己的相矛盾,所以我将删除我在回答中关于计时的内容,以便我可以进一步研究。感谢您的单挑。实际上,我认为“真实”计时测试需要使用随机列表值。
martineau 2010年

10

我想出了以下内容,您可以通过看到它maxmin以及其他类似列表中的功能:

因此,请考虑下一个示例列表,以找出最大值在列表中的位置a

>>> a = [3,2,1, 4,5]

使用发电机 enumerate铸造

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

在这一点上,我们可以提取的位置最大值

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

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

如您所见,在自key变量中,可以通过定义适当的lambda来找到任何可迭代对象的最大值。

我希望它能有所作为。

PD:@PaulOyster在评论中指出。随着Python 3.xminmax允许新的关键字default是避免引发异常ValueError时的说法是空列表。max(enumerate(list), key=(lambda x:x[1]), default = -1)


2
这是一个更好的解决方案,因为它涉及单次通过。不过,有一些注释:1.无需list()枚举; 2。最好在lambda上加上括号; 3。min()和max()现在具有默认参数(在空输入中返回),因此可以使用它(例如,默认值= -1)以避免ValueError异常,并且4.请更改为max(),因为这是原始问题。
Paul Oyster

大约3项,是的,它仅适用于Python3.x。我会提到这一点。并修复所有其他问题。;)
jonaprieto 2015年

2
当它在列表中出现多次时,只会发现其中一个最大价值元素(第一个)的位置,因此无法回答所提出的问题。
martineau

8

我无法复制@martineau引用的@ SilentGhost-beating性能。这是我的比较工作:

=== 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

在Windows XP SP3上运行Python 2.7的老式笔记本电脑的结果:

>\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

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

您还可以使用numpy软件包:

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

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

如果要将其转到列表:

maximum_indices_list = maximum_indices.tolist()


5

也可以通过使用以下方法来实现给出第一个外观的解决方案numpy

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

3

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

查找最大列表元素索引的Python方法是

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

一个通过。但是,它比@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

2

这是最大值及其出现的索引:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> 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]
>>> for i, x in enumerate(a):
...     d[x].append(i)
... 
>>> k = max(d.keys())
>>> print k, d[k]
55 [9, 12]

后来:对于@SilentGhost感到满意

>>> from itertools import takewhile
>>> import heapq
>>> 
>>> def popper(heap):
...     while heap:
...         yield heapq.heappop(heap)
... 
>>> 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]
>>> h = [(-x, i) for i, x in enumerate(a)]
>>> heapq.heapify(h)
>>> 
>>> largest = heapq.heappop(h)
>>> indexes = [largest[1]] + [x[1] for x in takewhile(lambda large: large[0] == largest[0], popper(h))]
>>> print -largest[0], indexes
55 [9, 12]

您知道这是多么低效吗?
SilentGhost

1
合理化:(1)“过早的优化就是……等等”。(2)可能无关紧要。(3)仍然是一个很好的解决方案。也许我会重新编码以使用heapq-找到最大数量将是微不足道的。
hughdbrown 2010年

虽然我很乐意看到您的heapq解决方案,但我怀疑它是否可行。
SilentGhost 2010年

2

列表理解但没有列举的类似想法

m = max(a)
[i for i in range(len(a)) if a[i] == m]

我不是拒绝投票的人,但是请注意,这看起来并不太好,效果也不佳:在Python中遍历索引而不是通过列表进行迭代非常尴尬,请尝试避免这种情况。同样,由于a[i]调用,它肯定比带有枚举的解决方案要慢。
哟,

1

仅一行:

idx = max(range(len(a)), key = lambda i: a[i])

很好,但是它不返回所有索引,只是第一个。
iggy

1

如果要n在名为的列表中获取最大数字的索引,则data可以使用Pandas sort_values

pd.Series(data).sort_values(ascending=False).index[0:n]

0
import operator

def max_positions(iterable, key=None, reverse=False):
  if key is None:
    def key(x):
      return x
  if reverse:
    better = operator.lt
  else:
    better = operator.gt

  it = enumerate(iterable)
  for pos, item in it:
    break
  else:
    raise ValueError("max_positions: empty iterable")
    # note this is the same exception type raised by max([])
  cur_max = key(item)
  cur_pos = [pos]

  for pos, item in it:
    k = key(item)
    if better(k, cur_max):
      cur_max = k
      cur_pos = [pos]
    elif k == cur_max:
      cur_pos.append(pos)

  return cur_max, cur_pos

def min_positions(iterable, key=None, reverse=False):
  return max_positions(iterable, key, not reverse)

>>> L = range(10) * 2
>>> L
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> max_positions(L)
(9, [9, 19])
>>> min_positions(L)
(0, [0, 10])
>>> max_positions(L, key=lambda x: x // 2, reverse=True)
(0, [0, 1, 10, 11])

0

这段代码不像之前发布的答案那样复杂,但可以运行:

m = max(a)
n = 0    # frequency of max (a)
for number in a :
    if number == m :
        n = n + 1
ilist = [None] * n  # a list containing index values of maximum number in list a.
ilistindex = 0
aindex = 0  # required index value.    
for number in a :
    if number == m :
        ilist[ilistindex] = aindex
        ilistindex = ilistindex + 1
    aindex = aindex + 1

print ilist

上面的代码中的ilist将包含列表中最大数量的所有位置。


0

您可以通过多种方式进行操作。

传统的旧方法是

maxIndexList = list() #this list will store indices of maximum values
maximumValue = max(a) #get maximum value of the list
length = len(a)       #calculate length of the array

for i in range(length): #loop through 0 to length-1 (because, 0 based indexing)
    if a[i]==maximumValue: #if any value of list a is equal to maximum value then store its index to maxIndexList
        maxIndexList.append(i)

print(maxIndexList) #finally print the list

不计算列表长度并将最大值存储到任何变量的另一种方法,

maxIndexList = list()
index = 0 #variable to store index
for i in a: #iterate through the list (actually iterating through the value of list, not index )
    if i==max(a): #max(a) returns a maximum value of list.
        maxIndexList.append(index) #store the index of maximum value
index = index+1 #increment the index

print(maxIndexList)

我们可以用Pythonic和聪明的方式做到这一点!仅使用一行列表就能理解列表

maxIndexList = [i for i,j in enumerate(a) if j==max(a)] #here,i=index and j = value of that index

我所有的代码都在Python 3中。

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.