关于python:在列表上使用max()/ min()获取返回的最大或最小项的索引

Getting the index of the returned max or min item using max()/min() on a list

我在清单上使用Python的maxmin函数用于minimax算法,并且我需要max()min()返回的值的索引。 换句话说,我需要知道哪个移动产生了最大(第一玩家回合)或最小(第二玩家)值。

1
2
3
4
5
6
7
8
9
10
11
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)

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


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

避免在其他答案中出现带有itemgetter()的解决方案,而改用

1
index_min = min(xrange(len(values)), key=values.__getitem__)

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

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

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

即使在以下情况下将其应用于纯Python列表,也将比第一个解决方案更快。

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

正如该基准所指出的:
enter image description here

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


1
2
3
4
if isMinLevel:
    return values.index(min(values))
else:
    return values.index(max(values))


如果您枚举列表中的项目,则可以同时找到min / max索引和值,但是要对列表的原始值执行min / max。像这样:

1
2
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))

这样,列表将只遍历一次最小值(或最大值)。


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

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


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

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

1
2
list=[1.1412, 4.3453, 5.8709, 0.1314]
list.index(min(list))

将给您第一个最小索引。


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

原来是numpy的argmin,

1
numpy.argmin(x)

对于足够大的列表,即使从输入listnumpy.array的隐式转换,它也是最快的方法。

enter image description here

生成绘图的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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,
    )


使用一个numpy数组和argmax()函数

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


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

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


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

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

比很多选择要简单得多。


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

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

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


使用numpy模块的函数numpy.where

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

对于最小值索引:

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

对于最大值索引:

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

实际上,此功能更强大。您可以进行各种布尔运算
对于3到60之间的值的索引:

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


使用内置的enumerate()max()函数以及max()函数的可选key参数和一个简单的lambda表达式,这完全可以实现:

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

max()的文档中,它说key参数需要一个与list.sort()函数类似的函数。另请参阅排序方式。

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


假设您有一个清单,例如:

1
a = [9,8,7]

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

拉链方式

1
2
3
4
5
6
7
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)

列举方法

1
2
3
4
5
6
7
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)


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

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


为什么要先添加索引然后再颠倒索引呢? Enumerate()函数只是zip()函数用法的一种特殊情况。让我们以适当的方式使用它:

1
2
3
4
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)

只是已经说过的一小部分。
values.index(min(values))似乎返回min的最小索引。以下是最大的索引:

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

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

遍历所有事件

1
2
3
4
5
    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)缓存在循环外可能是一个更好的主意。


如果您不想导入其他模块,则可以使用一种简单的方法在列表中查找值最小的索引:

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

然后选择第一个:

1
choosen = indexes_with_min_value[0]

就那么简单 :

1
2
3
stuff = [2, 4, 8, 15, 11]

index = stuff.index(max(stuff))


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

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

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


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

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

要获得的不仅仅是第一个,请使用sort方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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)]