使用列表上的max()/ min()获取返回的最大或最小项目的索引

问题:使用列表上的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)

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

I’m using Python’s max and min functions on lists for a minimax algorithm, and I need the index of the value returned by max() or min(). In other words, I need to know which move produced the max (at a first player’s turn) or min (second player) value.

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)

I need to be able to return the actual index of the min or max value, not just the value.


回答 0

如果isMinLevel:
    返回values.index(min(values))
其他:
    返回values.index(max(values))
if isMinLevel:
    return values.index(min(values))
else:
    return values.index(max(values))

回答 1

假设您有一个list 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情况完全相同

Say that you have a list values = [3,6,1,5], and need the index of the smallest element, i.e. index_min = 2 in this case.

Avoid the solution with itemgetter() presented in the other answers, and use instead

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

because it doesn’t require to import operator nor to use enumerate, and it is always faster(benchmark below) than a solution using itemgetter().

If you are dealing with numpy arrays or can afford numpy as a dependency, consider also using

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

This will be faster than the first solution even if you apply it to a pure Python list if:

  • it is larger than a few elements (about 2**4 elements on my machine)
  • you can afford the memory copy from a pure list to a numpy array

as this benchmark points out:

I have run the benchmark on my machine with python 2.7 for the two solutions above (blue: pure python, first solution) (red, numpy solution) and for the standard solution based on itemgetter() (black, reference solution). The same benchmark with python 3.5 showed that the methods compare exactly the same of the python 2.7 case presented above


回答 2

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

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

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

You can find the min/max index and value at the same time if you enumerate the items in the list, but perform min/max on the original values of the list. Like so:

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

This way the list will only be traversed once for min (or max).


回答 3

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

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

If you want to find the index of max within a list of numbers (which seems your case), then I suggest you use numpy:

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

回答 4

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

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

Possibly a simpler solution would be to turn the array of values into an array of value,index-pairs, and take the max/min of that. This would give the largest/smallest index that has the max/min (i.e. pairs are compared by first comparing the first element, and then comparing the second element if the first ones are the same). Note that it’s not necessary to actually create the array, because min/max allow generators as input.

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

回答 5

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

将给您第一个最小值的索引。

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

Will give you first index of minimum.


回答 6

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

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

I think the best thing to do is convert the list to a numpy array and use this function :

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

回答 7

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

原来那是numpy的argmin

numpy.argmin(x)

即使足够大的列表(从输入list到a 的隐式转换),它也是最快的方法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,
    )

I was also interested in this and compared some of the suggested solutions using perfplot (a pet project of mine).

Turns out that numpy’s argmin,

numpy.argmin(x)

is the fastest method for large enough lists, even with the implicit conversion from the input list to a numpy.array.


Code for generating the plot:

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,
    )

回答 8

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

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

Use a numpy array and the argmax() function

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

回答 9

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

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

比很多选择要简单得多。

After you get the maximum values, try this:

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

Much simpler than a lot of options.


回答 10

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

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

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

I think the answer above solves your problem but I thought I’d share a method that gives you the minimum and all the indices the minimum appears in.

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

This passes the list twice but is still quite fast. It is however slightly slower than finding the index of the first encounter of the minimum. So if you need just one of the minima, use Matt Anderson‘s solution, if you need them all, use this.


回答 11

使用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])

Use numpy module’s function numpy.where

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

For index of minimum value:

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

For index of maximum value:

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

In fact, this function is much more powerful. You can pose all kinds of boolean operations For index of value between 3 and 60:

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

回答 12

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

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

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

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

This is simply possible using the built-in enumerate() and max() function and the optional key argument of the max() function and a simple lambda expression:

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

In the docs for max() it says that the key argument expects a function like in the list.sort() function. Also see the Sorting How To.

It works the same for min(). Btw it returns the first max/min value.


回答 13

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

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)

Say you have a list such as:

a = [9,8,7]

The following two methods are pretty compact ways to get a tuple with the minimum element and its index. Both take a similar time to process. I better like the zip method, but that is my taste.

zip method

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)

enumerate method

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)

回答 14

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

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

As long as you know how to use lambda and the “key” argument, a simple solution is:

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

回答 15

就那么简单 :

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

index = stuff.index(max(stuff))

Simple as that :

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

index = stuff.index(max(stuff))

回答 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)

Why bother to add indices first and then reverse them? Enumerate() function is just a special case of zip() function usage. Let’s use it in appropiate way:

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

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

    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)在循环外可能是一个更好的主意。

Just a minor addition to what has already been said. values.index(min(values)) seems to return the smallest index of min. The following gets the largest index:

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

The last line can be left out if the side effect of reversing in place does not matter.

To iterate through all occurrences

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

For the sake of brevity. It is probably a better idea to cache min(values), values.count(min) outside the loop.


回答 18

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

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]

A simple way for finding the indexes with minimal value in a list if you don’t want to import additional modules:

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

Then choose for example the first one:

choosen = indexes_with_min_value[0]

回答 19

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

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

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

Dont have high enough rep to comment on existing answer.

But for https://stackoverflow.com/a/11825864/3920439 answer

This works for integers, but does not work for array of floats (at least in python 3.6) It will raise TypeError: list indices must be integers or slices, not float


回答 20

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

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

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

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

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

If multiple items are maximal, the function returns the first one encountered. This is consistent with other sort-stability preserving tools such as sorted(iterable, key=keyfunc, reverse=True)[0]

To get more than just the first use the sort method.

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

回答 21

那这个呢:

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

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

What about this:

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

It creates a dictionary from the items in a as keys and their indexes as values, thus dict(zip(a,range(len(a))))[max(a)] returns the value that corresponds to the key max(a) which is the index of the maximum in a. I’m a beginner in python so I don’t know about the computational complexity of this solution.