使用列表中的max()/ min()获取返回的max或min项的索引

Kev*_*fin 395 python list max min

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

for i in range(9):
    newBoard = currentBoard.newBoardWithMove([i / 3, i % 3], player)

    if newBoard:
        temp = minMax(newBoard, depth + 1, not isMinLevel)  
        values.append(temp)

if isMinLevel:
    return min(values)
else:
    return max(values)
Run Code Online (Sandbox Code Playgroud)

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

gg3*_*349 431

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

避免itemgetter()在其他答案中提出的解决方案,而是使用

index_min = min(xrange(len(values)), key=values.__getitem__)
Run Code Online (Sandbox Code Playgroud)

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

如果您正在处理numpy数组或者可以numpy作为依赖项,请考虑使用

import numpy as np
index_min = np.argmin(values)
Run Code Online (Sandbox Code Playgroud)

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

  • 它大于几个元素(我机器上大约2**4个元素)
  • 你可以负担从纯列表到numpy数组的内存复制

正如这个基准指出: 在此输入图像描述

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

  • 哇,用图表对可能的解决方案进行了基准测试......我第一次看到这个问题了!真棒... (16认同)
  • len(list)以2的幂表示xtick标签?:-)让我们敏锐! (3认同)
  • @LindsayFowler`xrange()`现在已被弃用,您可以使用`range()` (3认同)
  • 我在[这个答案](/sf/answers/5388704401/)中做了一个小基准测试,其中包括“list.index”(因为上面的基准测试不包括它),这表明该方法使用`list.index` 几乎是此方法的两倍。 (3认同)

too*_*php 344

if isMinLevel:
    return values.index(min(values))
else:
    return values.index(max(values))

  • @Kashyap它实际上是O(N),而不是O(N ^ 2).在最小的情况下,首先评估min(值),即O(N),然后调用values.index(),它也是O(N).O(N)+ O(N)= O(N).索引的参数仅评估一次.它相当于:`tmp = min(values); return values.index(tmp)` (83认同)
  • @KevinGriffin,请注意,这只会让您获得最少/最多的几次出现.这可能不是你想要的,例如,如果有可能以相同的两种方式增加你的收益,但其中一个更能伤害另一个玩家.我不知道你是否需要考虑这个案例. (33认同)
  • @ShashiTunga [list].index() 仅返回某些内容的第一次出现,不保证它是排他的,最小值在列表中可能不是唯一的 (2认同)

Mat*_*son 320

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

import operator
min_index, min_value = min(enumerate(values), key=operator.itemgetter(1))
max_index, max_value = max(enumerate(values), key=operator.itemgetter(1))
Run Code Online (Sandbox Code Playgroud)

这样,列表只会在min(或max)中遍历一次.

  • 或者使用lambda:`key = lambda p:p [1]` (100认同)
  • `min([(j, i) for i, j in enumerate(values)])` 以避免昂贵的函数调用。 (5认同)
  • 不要忘记"导入运算符"以使其工作 (3认同)

小智 108

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

import numpy as np
ind = np.argmax(mylist)
Run Code Online (Sandbox Code Playgroud)

  • 如果最大值出现多次,则返回与第一次出现对应的索引。 (2认同)

Ant*_*t6n 35

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

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


And*_*ndy 28

list=[1.1412, 4.3453, 5.8709, 0.1314]
list.index(min(list))
Run Code Online (Sandbox Code Playgroud)

会给你第一个最小指数.


Nic*_*mer 14

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

原来那个numpy的argmin,

numpy.argmin(x)
Run Code Online (Sandbox Code Playgroud)

对于足够大的列表来说,这是最快的方法,即使从输入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,
    )
Run Code Online (Sandbox Code Playgroud)


cot*_*ail 10

有两个答案(12)包含基准,但由于某种原因,它们都没有包含list.index()在基准中,即使在这些答案之前至少 2 年发布的已接受答案中提出了建议。

list.index()是此页面上给出的最快选项,包括enumerate(涉及它的所有版本),__getitem__并且numpy.argmin.

此外,如果列表具有非唯一的最小值,并且您想要获取出现最小值的所有索引,list.index则 while 循环优于其他选项,例如 numpy 等enumerate。请注意,您可以通过传递起点(这是 的第二个参数list.index)来限制其搜索从特定索引开始,这对于性能至关重要,因为我们不想在 while 的每次迭代中从头开始搜索-环形。

# get the index of the minimum value
my_list = [1, 2, 0, 1]
idxmin = my_list.index(min(my_list))
print(idxmin)   # 2


# get all indices where the min value occurs
my_list = [1, 2, 3, 1]
idxmins = []
min_val = min(my_list)
pos = -1
while True:
    try:
        pos = my_list.index(min_val, pos+1)
        #                            ^^^^^   <---- pick up where we left off in the previous iteration
        idxmins.append(pos)
    except ValueError:
        break

print(idxmins)   # [0, 3]
Run Code Online (Sandbox Code Playgroud)

以下基准测试(在 Python 3.11.4 和 numpy 1.25.2 上执行)表明,list.index无论列表的长度如何,它的速度几乎是所有其他选项的两倍。左图还显示,对于长列表,其执行与( 和)getitem相同,这表明gg349Nico的基准测试已经过时。enumeratenumpy.argmin

右图显示,如果最小值不唯一,并且我们想要找到最小值的所有索引,那么在如上所述的 while 循环中,其性能比涉及或 numpy 的list.index竞争选项要好得多,尤其是对于长列表。enumerate

基准

用于生成上图的代码:

from operator import itemgetter
import numpy as np
import matplotlib.pyplot as plt
import perfplot


def enumerate_1(a):
    return min(enumerate(a), key=itemgetter(1))[0]


def np_argmin_1(a):
    return np.argmin(a)


def getitem(a):
    return min(range(len(a)), key=a.__getitem__)


def list_index_1(a):
    return a.index(min(a))


def enumerate_2(a):
    min_val = min(a)
    return [i for i, v in enumerate(a) if v == min_val]


def np_argmin_2(a):
    arr = np.array(a)
    return np.arange(len(a))[arr==arr.min()]


def list_index_2(a):
    result = []
    min_val = min(a)
    pos = -1
    while True:
        try:
            pos = a.index(min_val, pos+1)
            result.append(pos)
        except ValueError:
            break
    return result


kernels_list = [[enumerate_1, list_index_1, np_argmin_1, getitem], 
                [enumerate_2, list_index_2, np_argmin_2]]
n_range = [2**k for k in range(1, 20)]
su = lambda n: list(range(n, 0, -1))
titles = ['Get index of a unique min value', 
          'Get indices of a non-unique min value']
labels = ['enumerate', 'list_index', 'np_argmin', 'getitem']
xlabel = 'List length'


fig, axs = plt.subplots(1, 2, figsize=(12, 5), facecolor='white', dpi=60)
for ax, ks, t in zip(axs, kernels_list, titles):
    plt.sca(ax)
    perfplot.plot(ks, n_range, su, None, labels, xlabel, t, relative_to=1)
    ax.xaxis.set_tick_params(labelsize=13)
plt.setp(axs, ylim=(0, 5), yticks=range(1, 6), 
         xlim=(1, 1100000), xscale='log', xticks=[1, 100, 10000, 1000000]);
fig.tight_layout();
fig.savefig('benchmark.png', dpi=60);
Run Code Online (Sandbox Code Playgroud)

  • @BorisVerkhovskiy 我不认为编辑遵循 SO 准则,因为它改变了作者的意图。也使我的回答的要点成为他们的观点,我认为这是不公平的。 (4认同)

alp*_*989 8

获得最大值后,请尝试以下操作:

max_val = max(list)
index_max = list.index(max_val)
Run Code Online (Sandbox Code Playgroud)

比许多选项简单得多.


小智 8

使用numpy数组和argmax()函数

 a=np.array([1,2,3])
 b=np.argmax(a)
 print(b) #2
Run Code Online (Sandbox Code Playgroud)


Aks*_*jan 8

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

a = np.array(list)
idx = np.argmax(a)
Run Code Online (Sandbox Code Playgroud)


小智 6

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

minval = min(mylist)
ind = [i for i, v in enumerate(mylist) if v == minval]
Run Code Online (Sandbox Code Playgroud)

这两次通过了列表,但仍然非常快。但是,这比找到最小值的第一次遇到的索引要慢一些。因此,如果您仅需要一个最小值,请使用Matt Anderson的解决方案,如果您需要全部解决方案,请使用此解决方案。

  • 我喜欢这个,因为它使用基础 Python,而且我发现列表理解比 itemgetter、lambda 等更容易理解(并且足够灵活以解决各种任务,例如这个......) (2认同)

Ish*_*mar 6

使用numpy模块的函数numpy.where

import numpy as n
x = n.array((3,3,4,7,4,56,65,1))
Run Code Online (Sandbox Code Playgroud)

对于最小值索引:

idx = n.where(x==x.min())[0]
Run Code Online (Sandbox Code Playgroud)

对于最大值的索引:

idx = n.where(x==x.max())[0]
Run Code Online (Sandbox Code Playgroud)

实际上,这个功能要强大得多.您可以构造各种布尔运算对于3到60之间的值索引:

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


Sim*_*sch 5

使用内置enumerate()max()函数以及函数的可选key参数max()和简单的lambda表达式,就可以轻松实现:

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

在文档中max()说,该key参数需要一个类似于函数中的list.sort()函数。另请参阅“ 排序方法”

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


Vei*_*iga 5

您可以将 lambda 作为key=参数传递给max()/ min()

max_index = max(range(len(my_list)), key=lambda index: my_list[index])
Run Code Online (Sandbox Code Playgroud)


Pab*_*MPA 5

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

a = [9,8,7]
Run Code Online (Sandbox Code Playgroud)

以下两种方法是获取具有最小元素及其索引的元组的非常紧凑的方法。两者都需要相似的时间来处理。我更喜欢 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)
Run Code Online (Sandbox Code Playgroud)

枚举方法

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)
Run Code Online (Sandbox Code Playgroud)


小智 5

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

df[column].idxmax()