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