【问题标题】:Getting the index of the returned max or min item using max()/min() on a list使用列表中的 max()/min() 获取返回的最大或最小项的索引
【发布时间】:2011-01-29 06:18:04
【问题描述】:

我在列表中使用 Python 的 maxmin 函数来实现 minimax 算法,我需要 max()min() 返回的值的索引。换句话说,我需要知道哪个动作产生了最大值(轮到第一个玩家)或最小值(第二个玩家)。

for i in range(9):
    new_board = current_board.new_board_with_move([i / 3, i % 3], player)

    if new_board:
        temp = min_max(new_board, depth + 1, not is_min_level)  
        values.append(temp)

if is_min_level:
    return min(values)
else:
    return max(values)

我需要能够返回最小值或最大值的实际索引,而不仅仅是值。

【问题讨论】:

  • 内置divmod 的存在是为了避免说太多[i / 3, i % 3]

标签: python list max min


【解决方案1】:

假设你有一个列表values = [3,6,1,5],并且需要最小元素的索引,在这种情况下是index_min = 2

避免使用其他答案中提供的itemgetter() 的解决方案,并改用

index_min = min(range(len(values)), key=values.__getitem__)

因为它不需要import operator 也不需要使用enumerate,而且它总是比使用itemgetter() 的解决方案更快(下面的基准)。

如果您正在处理 numpy 数组或负担得起 numpy 作为依赖项,请考虑使用

import numpy as np
index_min = np.argmin(values)

这将比第一个解决方案更快,即使您将其应用于纯 Python 列表,如果:

  • 它比几个元素大(我的机器上大约有 2**4 个元素)
  • 您可以负担从纯列表到numpy 数组的内存副本

正如该基准所指出的:

我已经在我的机器上使用 python 2.7 运行了上述两种解决方案(蓝色:纯 python,第一个解决方案)(红色,numpy 解决方案)和基于 itemgetter() 的标准解决方案(黑色,参考解决方案)的基准测试. 与 python 3.5 相同的基准测试表明,这些方法与上面介绍的 python 2.7 案例完全相同

【讨论】:

  • 非常强的+1。我喜欢建议的解决方案的基准测试和您总结的经验法则。正如我在下面的另一个答案中所建议的那样,您能否提供(或链接到)您的测试代码,以便其他人可以重现您的结果?机器和库会随着时间而变化,因此可以与其他解决方案进行比较。
  • np.argmin 不适用于浮点数。只有第一个建议适用于整数和浮点数。
  • 我觉得你错了,试试import numpy as np; x = [2.3, -1.4]; np.argmin(x)。你会看到argmin 也适用于浮动
【解决方案2】:
if is_min_level:
    return values.index(min(values))
else:
    return values.index(max(values))

【讨论】:

  • @KevinGriffin,请注意,这只会让您获得可能出现的几次最小值/最大值之一。这可能不是您想要的,例如,如果有可能以同样的两种方式增加您的收益,但其中一种方式对另一个玩家的伤害更大。不知道你是否需要考虑这种情况。
  • @Kashyap 实际上是 O(N),而不是 O(N^2)。在 min 情况下,首先计算 min(values),即 O(N),然后调用 values.index(),这也是 O(N)。 O(N) + O(N) = O(N)。 index 的参数只计算一次。相当于:tmp = min(values); return values.index(tmp)
  • @too much php 出现重复元素怎么办?
  • @ShashiTunga [list].index() 只返回第一次出现的东西,不保证它是独占的,最小值在列表中可能不是唯一的
  • 你也可以内联ifreturn values.index(min(values) if is_min_value else max(values))
【解决方案3】:

如果枚举列表中的项目,可以同时找到最小值/最大值索引和值,但对列表的原始值执行最小值/最大值。像这样:

import operator
min_index, min_value = min(enumerate(values), key=operator.itemgetter(1))
max_index, max_value = max(enumerate(values), key=operator.itemgetter(1))

这样,列表只会被遍历一次 min(或 max)。

【讨论】:

  • 或使用 lambda:key=lambda p: p[1]
  • min([(j, i) for i, j in enumerate(values)]) 以避免昂贵的函数调用。
【解决方案4】:

如果您想在数字列表中找到 max 的索引(这似乎是您的情况),那么我建议您使用 numpy:

import numpy as np
ind = np.argmax(mylist)

【讨论】:

  • 如果最大值多次出现,则返回第一次出现对应的索引。
【解决方案5】:

可能更简单的解决方案是将值数组转换为值数组,索引对,并取其中的最大值/最小值。这将给出具有最大/最小值的最大/最小索引(即通过首先比较第一个元素,然后比较第二个元素(如果第一个元素相同)来比较对)。请注意,实际上不必创建数组,因为 min/max 允许生成器作为输入。

values = [3,4,5]
(m,i) = max((v,i) for i,v in enumerate(values))
print (m,i) #(5, 2)

【讨论】:

    【解决方案6】:
    seq=[1.1412, 4.3453, 5.8709, 0.1314]
    seq.index(min(seq))
    

    会给你第一个最小值的索引。

    【讨论】:

      【解决方案7】:

      我认为最好的办法是将列表转换为numpy array 并使用此功能:

      a = np.array(list)
      idx = np.argmax(a)
      

      【讨论】:

        【解决方案8】:

        我也对此感兴趣,并使用perfplot(我的一个宠物项目)比较了一些建议的解决方案。

        原来numpy's argmin

        numpy.argmin(x)
        

        对于足够大的列表来说是最快的方法,即使从输入 list 隐式转换为 numpy.array


        生成情节的代码:

        import numpy
        import operator
        import perfplot
        
        
        def min_enumerate(a):
            return min(enumerate(a), key=lambda x: x[1])[0]
        
        
        def min_enumerate_itemgetter(a):
            min_index, min_value = min(enumerate(a), key=operator.itemgetter(1))
            return min_index
        
        
        def getitem(a):
            return min(range(len(a)), key=a.__getitem__)
        
        
        def np_argmin(a):
            return numpy.argmin(a)
        
        
        perfplot.show(
            setup=lambda n: numpy.random.rand(n).tolist(),
            kernels=[
                min_enumerate,
                min_enumerate_itemgetter,
                getitem,
                np_argmin,
                ],
            n_range=[2**k for k in range(15)],
            logx=True,
            logy=True,
            )
        

        【讨论】:

        • 请注意,两年多前我的回答中已经发布了相同的结论,并提供了有关何时以及为什么可以使用或不使用 argmin 的更多信息。考虑删除答案,这也没有为同一页面上已经提出的内容提供价值。还考虑查看您在 SO 上的其他类似行为的答案:您似乎没有引用在性能分析中提供最佳解决方案的实际答案。这是相当糟糕的,尤其是对于那些拥有超过 10K 代表并且已经存在足够长的时间以更好地了解的人。
        • @gg349,非常好的观点,但他确实提供了生成结果的源代码,这使得这很容易重现并适用于比较其他解决方案。我同意他可能会考虑将此答案作为重复项删除,但也许您可以通过包含或链接到您使用的代码来为您的答案增加价值?
        【解决方案9】:

        我认为上面的答案可以解决您的问题,但我想我会分享一种方法,该方法可以为您提供最小值和最小值出现的所有索引。

        minval = min(mylist)
        ind = [i for i, v in enumerate(mylist) if v == minval]
        

        这通过列表两次,但仍然相当快。然而,它比找到第一次遇到最小值的索引要慢一些。因此,如果您只需要其中一个最小值,请使用Matt Anderson 的解决方案,如果您需要全部,请使用它。

        【讨论】:

        • 我喜欢这个,因为它使用基础 Python,而且我发现列表理解比 itemgetter、lambda 等更容易理解(并且足够灵活,可以解决各种任务,比如这个......)
        • 原始的。我更喜欢这个。
        • 我非常感谢这个答案,因为它处理多次出现,而大多数其他答案只处理一次出现,这对我来说是不可用的。 +1
        • 简约中有优雅。这个答案对于初学者来说很容易理解,同时提供了有用的输出。
        【解决方案10】:

        得到最大值后,试试这个:

        max_val = max(list)
        index_max = list.index(max_val)
        

        比许多选项简单得多。

        【讨论】:

          【解决方案11】:

          使用 numpy 数组和 argmax() 函数

           a=np.array([1,2,3])
           b=np.argmax(a)
           print(b) #2
          

          【讨论】:

            【解决方案12】:

            使用numpy模块的函数numpy.where

            import numpy as n
            x = n.array((3,3,4,7,4,56,65,1))
            

            对于最小值的索引:

            idx = n.where(x==x.min())[0]
            

            对于最大值的索引:

            idx = n.where(x==x.max())[0]
            

            其实这个功能要强大得多。您可以提出各种布尔运算 对于 3 到 60 之间的值索引:

            idx = n.where((x>3)&(x<60))[0]
            idx
            array([2, 3, 4, 5])
            x[idx]
            array([ 4,  7,  4, 56])
            

            【讨论】:

            • python 中的索引从 0 开始。返回的索引应为 6(对于 65),而您的代码返回 7(OP 的问题是“获取索引 ...”)
            • 在命令中,我查询了索引为 7 的最小值(此处为:1)的索引。65 是数组中元素的最大值。如果你输入: n.where(x==x.max())[0] 你会得到最大值的索引。这里的值是 65。它的索引将是 6
            • 使用 numpy:可能在此应用程序中被禁止。但是如果你打算使用 numpy,你最好只使用 argmin() 而不是你在这里所做的。
            • 谢谢@RBF06 我会去看看。
            【解决方案13】:

            Pandas 现在有了更温和的解决方案,试试吧:

            df[column].idxmax()

            【讨论】:

              【解决方案14】:

              使用内置的enumerate()max() 函数以及max() 函数的可选key 参数和一个简单的lambda 表达式很容易做到这一点:

              theList = [1, 5, 10]
              maxIndex, maxValue = max(enumerate(theList), key=lambda v: v[1])
              # => (2, 10)
              

              max() 的文档中,它说key 参数需要一个类似于list.sort() 函数的函数。另请参阅Sorting How To

              min() 的工作原理相同。顺便说一句,它返回第一个最大值/最小值。

              【讨论】:

              • 迟到但最好的答案(如果您不需要速度)。
              【解决方案15】:

              假设您有一个列表,例如:

              a = [9,8,7]
              

              以下两种方法是获取具有最小元素及其索引的元组的非常紧凑的方法。两者都需要相似时间来处理。我更喜欢 zip 方法,但这是我的口味。

              压缩方式

              element, index = min(list(zip(a, range(len(a)))))
              
              min(list(zip(a, range(len(a)))))
              (7, 2)
              
              timeit min(list(zip(a, range(len(a)))))
              1.36 µs ± 107 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
              

              枚举方法

              index, element = min(list(enumerate(a)), key=lambda x:x[1])
              
              min(list(enumerate(a)), key=lambda x:x[1])
              (2, 7)
              
              timeit min(list(enumerate(a)), key=lambda x:x[1])
              1.45 µs ± 78.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
              

              【讨论】:

                【解决方案16】:

                为什么要先添加索引然后反转它们? Enumerate() 函数只是 zip() 函数使用的一个特例。让我们以适当的方式使用它:

                my_indexed_list = zip(my_list, range(len(my_list)))
                
                min_value, min_index = min(my_indexed_list)
                max_value, max_index = max(my_indexed_list)
                

                【讨论】:

                  【解决方案17】:

                  只要你知道如何使用 lambda 和 "key" 参数,一个简单的解决方案是:

                  max_index = max( range( len(my_list) ), key = lambda index : my_list[ index ] )
                  

                  【讨论】:

                  • 非常干净!与公认的答案不同,这是 true O(n),对吗?我知道 O(2n) 被认为是 O(n),但是对于非常大的 n 它可能会明显变慢。
                  【解决方案18】:

                  就这么简单:

                  stuff = [2, 4, 8, 15, 11]
                  
                  index = stuff.index(max(stuff))
                  

                  【讨论】:

                    【解决方案19】:

                    只是对已经说过的内容的一个小补充。 values.index(min(values)) 似乎返回 min 的最小索引。以下获取最大索引:

                        values.reverse()
                        (values.index(min(values)) + len(values) - 1) % len(values)
                        values.reverse()
                    

                    如果原地反转的副作用无关紧要,可以省略最后一行。

                    遍历所有事件

                        indices = []
                        i = -1
                        for _ in range(values.count(min(values))):
                          i = values[i + 1:].index(min(values)) + i + 1
                          indices.append(i)
                    

                    为了简洁起见。在循环外缓存min(values), values.count(min) 可能是一个更好的主意。

                    【讨论】:

                    • reversed(…) 而不是 ….reverse() 可能更可取,因为它不会发生变异并且无论如何都会返回生成器。并且所有出现也可能是minv = min(values); indices = [i for i, v in enumerate(values) if v == minv]
                    【解决方案20】:

                    如果您不想导入额外的模块,一种在列表中查找具有最小值的索引的简单方法:

                    min_value = min(values)
                    indexes_with_min_value = [i for i in range(0,len(values)) if values[i] == min_value]
                    

                    然后选择例如第一个:

                    choosen = indexes_with_min_value[0]
                    

                    【讨论】:

                      【解决方案21】:

                      没有足够高的代表来评论现有答案。

                      但是对于https://stackoverflow.com/a/11825864/3920439的回答

                      这适用于整数,但不适用于浮点数组(至少在 python 3.6 中) 它将引发TypeError: list indices must be integers or slices, not float

                      【讨论】:

                        【解决方案22】:

                        假设您有一个以下列表my_list = [1,2,3,4,5,6,7,8,9,10],并且我们知道如果我们这样做max(my_list),它将返回10,而min(my_list) 将返回1。现在我们要获取最大或最小元素的索引,我们可以执行以下操作。

                        my_list = [1,2,3,4,5,6,7,8,9,10]
                        
                        max_value = max(my_list) # returns 10
                        max_value_index = my_list.index(max_value) # retuns 9
                        
                        #to get an index of minimum value
                        
                        min_value = min(my_list) # returns 1
                        min_value_index = my_list.index(min_value) # retuns 0

                        【讨论】:

                          【解决方案23】:

                          https://docs.python.org/3/library/functions.html#max

                          如果多个项目是最大的,该函数返回遇到的第一个。这与sorted(iterable, key=keyfunc, reverse=True)[0]等其他排序稳定性保持工具一致

                          要获得的不仅仅是第一次遇到的,请使用排序方法。

                          import operator
                          
                          x = [2, 5, 7, 4, 8, 2, 6, 1, 7, 1, 8, 3, 4, 9, 3, 6, 5, 0, 9, 0]
                          
                          min = False
                          max = True
                          
                          min_val_index = sorted( list(zip(x, range(len(x)))), key = operator.itemgetter(0), reverse = min )
                          
                          max_val_index = sorted( list(zip(x, range(len(x)))), key = operator.itemgetter(0), reverse = max )
                          
                          
                          min_val_index[0]
                          >(0, 17)
                          
                          max_val_index[0]
                          >(9, 13)
                          
                          import ittertools
                          
                          max_val = max_val_index[0][0]
                          
                          maxes = [n for n in itertools.takewhile(lambda x: x[0] == max_val, max_val_index)]
                          

                          【讨论】:

                            【解决方案24】:

                            这个呢:

                            a=[1,55,2,36,35,34,98,0]
                            max_index=dict(zip(a,range(len(a))))[max(a)]
                            
                            

                            它将a 中的项作为键并将它们的索引作为值创建一个字典,因此dict(zip(a,range(len(a))))[max(a)] 返回对应于键max(a) 的值,该键是a 中最大值的索引。我是 python 的初学者,所以我不知道这个解决方案的计算复杂性。

                            【讨论】:

                              猜你喜欢
                              • 2013-02-15
                              • 1970-01-01
                              • 2016-07-09
                              • 1970-01-01
                              • 2020-03-25
                              • 2021-02-12
                              • 2019-09-11
                              • 2018-07-09
                              • 1970-01-01
                              相关资源
                              最近更新 更多