【问题标题】:How to find all positions of the maximum value in a list?如何在列表中找到最大值的所有位置?
【发布时间】:2011-04-28 16:33:09
【问题描述】:

我有一个清单:

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

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

【问题讨论】:

    标签: python list indexing max


    【解决方案1】:
    a.index(max(a))
    

    将告诉您列表a 的最大值元素的第一个实例的索引。

    【讨论】:

    • 这只会让你得到第一个实例,他要求找到最大值的所有索引。您必须使用 slice 循环以获取每种情况下的剩余列表,并在不再找到该异常时处理该异常。
    • 我确实提到它只会给出第一个实例。如果你想要所有这些,SilentGhost 的解决方案更漂亮,更不容易出错。
    • 至少当我想到它时,这个问题明确要求在多个最大值的情况下列出一个列表......
    • 从技术上讲,您可以使用它来获取最大值元素的第一个实例,然后将其设置为一个大得离谱的负数,然后找到下一个最大值元素,但这太复杂了.
    • 明确表示“全部”。请不要发垃圾邮件,这里的目标是尽快帮助人们不要获得徽章和声誉(如果您真的想提供帮助,请删除您的答案)。
    【解决方案2】:
    >>> m = max(a)
    >>> [i for i, j in enumerate(a) if j == m]
    [9, 12]
    

    【讨论】:

    • 如果您不介意多次通过列表,那么很好的简短答案 - 这很可能。
    • 除了大 0 是 2n 外,列表迭代 2x,一次确定最大值,另一次找到最大值的位置。跟踪当前最大值及其位置的 for 循环对于非常长的列表可能更有效。
    • @radtek big O 只是 n。在大 O 中忽略前导系数
    • 理论上 O(N) 和 O(2N) 是相同的,但实际上,O(N) 肯定会运行更短的时间,尤其是当 N 接近无穷大时。
    【解决方案3】:

    这是最大值和它出现的索引:

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

    【讨论】:

    • 你知道这是多么低效吗?
    • 合理化:(1)“过早的优化是......等。” (2) 这可能无关紧要。 (3) 它仍然是一个很好的解决方案。也许我会重新编码它以使用heapq——找到最大值将是微不足道的。
    • 虽然我很想看看你的 heapq 解决方案,但我怀疑它会起作用。
    【解决方案4】:

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

    已编辑:解决@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
    

    【讨论】:

    • (1)空列表处理需要注意。应该返回 [] 广告(“返回列表”)。代码应该只是if not seq: return []。 (2) 循环中的测试方案是次优的:在随机列表中,条件val < maxval 将是最常见的,但上面的代码需要2次测试而不是1次。
    • +1 到@John Machin 的评论,因为它发现了与文档字符串的不一致,并且不让我发布次优代码。老实说,由于答案已经被接受,我失去了继续研究答案的动力,因为我认为几乎没有人会再看它——而且它比其他人的要长得多。
    • @martineau:“接受”的答案不一定是“可接受的”。我通常会阅读所有答案。包括你的修订。现在在 == 而不是 2 的罕见情况下进行 3 次测试——您的 elif 条件将始终为真。
    • @John Machin:我受到了很大的启发并进一步修改了它。现在它减少了最低限度的额外测试,以及一些其他的调整。感谢您的 cmets 和建设性的批评。我自己抓住了永远真实的elif,FWIW。 ;-)
    • @John Machin:嗯,你的计时结果似乎与我自己的相矛盾,所以我将删除我在回答中关于计时的内容,以便我可以进一步了解发生了什么。感谢您的提醒。实际上,我认为“真正的”时序测试需要使用随机列表值。
    【解决方案5】:

    我无法重现 @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
    

    在 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
    

    【讨论】:

      【解决方案6】:
      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])
      

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

        • 我不是反对者,但请注意,这看起来不太好,并且性能不佳:在 Python 中遍历索引而不是列表非常尴尬,您尝试避免这种情况。同样,由于a[i] 调用,它肯定比使用枚举的解决方案慢。
        【解决方案8】:

        你也可以使用 numpy 包:

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

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

        如果你想把它变成一个列表:

        maximum_indices_list = maximum_indices.tolist()
        

        【讨论】:

          【解决方案9】:

          我想出了以下方法,正如您所见,它可以与 maxmin 和其他类似列表的函数一起使用:

          所以,请考虑下一个示例列表,找出列表中最大值的位置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 来找到任何可迭代对象的最大值。

          我希望它有所贡献。

          PD:正如@PaulOyster 在评论中指出的那样。使用Python 3.xminmax 允许使用新关键字default,以避免在参数为空列表时引发异常ValueErrormax(enumerate(list), key=(lambda x:x[1]), default = -1)

          【讨论】:

          • 这是一个更好的解决方案,因为它涉及单遍。但是有一些 cmets:1. 不需要 list() 枚举,2. lambda 最好用括号括起来,3. min() 和 max() 现在有一个默认参数(在空输入时返回),所以可以使用它(例如,默认值 =-1)以避免 ValueError 异常,以及 4. 请更改为 max(),因为这是最初的问题。
          • 大约 3 项,是的,它只适用于 Python 3.x。我会提到这一点。并修复了其他所有内容。 ;)
          • 这只会找到一个最大值元素(第一个)在列表中多次出现时的位置,因此不回答所提出的问题。
          • 此解决方案与 OP 所要求的略有不同,但如果我们只想一次性找到最大索引,这似乎是一种更好的方法。我建议使用default = (None, None),因为它适合返回类型,以防我分配给一些变量,例如max_index, max_value = max(enumerate(list), key=(lambda x:x[1]), default = (None, None))
          【解决方案10】:

          此代码不像之前发布的答案那么复杂,但它会起作用:

          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将包含列表中最大数的所有位置。

          【讨论】:

            【解决方案11】:

            只有一行:

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

            【讨论】:

            • 很好,但它不会返回所有索引,只返回第一个。
            【解决方案12】:

            @shash answered this elsewhere

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

            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
            

            【讨论】:

              【解决方案13】:
              >>> max(enumerate([1,2,3,32,1,5,7,9]),key=lambda x: x[1])
              >>> (3, 32)
              

              【讨论】:

              • 这是错误的。尝试将最大的数字放在列表的中间。
              • 这是错误的。问题说“找到最大值的所有位置”。
              【解决方案14】:
              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
              

              这就是我通常的做法。

              【讨论】:

                【解决方案15】:

                您可以通过多种方式做到这一点。

                旧的传统方式是,

                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 中。

                【讨论】:

                  【解决方案16】:

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

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

                  【讨论】:

                    【解决方案17】:

                    还有一个只给出第一次出现的解决方案,可以通过使用numpy来实现:

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

                    【讨论】:

                      【解决方案18】:

                      这是一个简单的单通道解决方案。

                      import math
                      nums = [32, 37, 28, 30, 37, 25, 55, 27, 24, 35, 55, 23, 31]
                      
                      max_val = -math.inf
                      res = []
                      
                      for i, val in enumerate(nums):
                          if(max_val < val):
                              max_val = val
                              res = [i]
                          elif(max_val == val):
                              res.append(i)
                      print(res)
                      

                      【讨论】:

                        猜你喜欢
                        • 2021-09-06
                        • 2021-12-19
                        • 1970-01-01
                        • 1970-01-01
                        • 2019-07-05
                        • 1970-01-01
                        • 1970-01-01
                        • 2019-06-13
                        相关资源
                        最近更新 更多