Obtenir l'index de l'élément Max ou min renvoyé en utilisant max()/min() sur une liste
J'utilise les fonctions max
et min
de Python sur les listes pour un algorithme minimax, et j'ai besoin de l'index de la valeur retournée par max()
ou min()
. En d'autres termes, j'ai besoin de savoir quel mouvement a produit la valeur max (au tour d'un premier joueur) ou min (deuxième joueur).
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)
Je dois pouvoir retourner l'index réel de la valeur min ou max, pas seulement la valeur.
20 réponses
if isMinLevel: return values.index(min(values)) else: return values.index(max(values))
Dites que vous avez une liste values = [3,6,1,5]
, et avez besoin de l'index du plus petit élément, c'est-à-dire index_min = 2
dans ce cas.
Évitez la solution avec itemgetter()
présentée dans les autres réponses, et utilisez à la place
index_min = min(xrange(len(values)), key=values.__getitem__)
Parce qu'il ne nécessite pas de import operator
ni d'utiliser enumerate
, et il est toujours plus rapide(benchmark ci-dessous) qu'une solution utilisant itemgetter()
.
Si vous avez affaire à des tableaux numpy ou si vous pouvez vous permettre numpy
en tant que dépendance, envisagez également d'utiliser
import numpy as np
index_min = np.argmin(values)
Ce sera plus rapide que la première solution même si vous l'appliquez à une liste Python pure si:
- , il est plus grand que quelques éléments (environ 2**4 éléments sur ma machine)
- Vous pouvez vous permettre la copie mémoire d'une liste pure vers un tableau
numpy
Comme le souligne ce point de repère:
J'ai exécuté le benchmark sur ma machine avec Python 2.7 pour les deux solutions ci-dessus (bleu: Python pur, première solution) (rouge, solution numpy) et pour la solution standard basée sur itemgetter()
(noir, solution de référence).
Le même benchmark avec Python 3.5 a montré que les méthodes comparent exactement la même chose du cas Python 2.7 présenté ci-dessus
Vous pouvez trouver l'index et la valeur min/max en même temps si vous énumérez les éléments de la liste, mais effectuez min/max sur les valeurs d'origine de la liste. Comme ça:
import operator
min_index, min_value = min(enumerate(values), key=operator.itemgetter(1))
max_index, max_value = max(enumerate(values), key=operator.itemgetter(1))
De cette façon, la liste ne sera parcourue qu'une fois pour min (ou max).
Si vous voulez trouver l'index de max dans une liste de nombres (ce qui semble être votre cas), alors je vous suggère d'utiliser numpy:
import numpy as np
ind = np.argmax(mylist)
Peut-être une solution plus simple serait de transformer le tableau de valeurs en un tableau de valeur,de paires d'index, et de prendre le max/min de cela. Cela donnerait l'indice le plus grand/le plus petit qui a le max / min (c'est-à-dire que les paires sont comparées en comparant d'abord le premier élément, puis en comparant le deuxième élément si les premiers sont les mêmes). Notez qu'il n'est pas nécessaire de créer réellement le tableau, car min/max autorise les générateurs en entrée.
values = [3,4,5]
(m,i) = max((v,i) for i,v in enumerate(values))
print (m,i) #(5, 2)
list=[1.1412, 4.3453, 5.8709, 0.1314]
list.index(min(list))
Vous donnera le premier index du minimum.
J'étais également intéressé par cela et j'ai comparé certaines des solutions suggérées en utilisant perfplot (un de mes projets pet).
S'avère que argmin de numpy ,
numpy.argmin(x)
Est la méthode la plus rapide pour les listes assez grandes, même avec la conversion implicite de l'entrée list
à un numpy.array
.
Code pour générer le tracé:
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,
)
Utilisez la fonction numpy du module numpy.où
import numpy as n
x = n.array((3,3,4,7,4,56,65,1))
Pour l'indice de valeur minimale:
idx = n.where(x==x.min())[0]
Pour l'indice de valeur maximale:
idx = n.where(x==x.max())[0]
En fait, cette fonction est beaucoup plus puissant. Vous pouvez poser toutes sortes d'opérations booléennes Pour l'indice de valeur entre 3 et 60:
idx = n.where((x>3)&(x<60))[0]
idx
array([2, 3, 4, 5])
x[idx]
array([ 4, 7, 4, 56])
Ceci est simplement possible en utilisant les fonctions enumerate()
et max()
intégrées et l'argument key
facultatif de la fonction max()
et une expression lambda simple:
theList = [1, 5, 10]
maxIndex, maxValue = max(enumerate(theList), key=lambda v: v[1])
# => (2, 10)
Dans les docs pour max()
il est dit que la key
argument s'attend à une fonction comme dans l'list.sort()
fonction. Voir aussi le Tri comment .
Cela fonctionne de la même manière pour min()
. Btw il renvoie la première valeur max / min.
Tant que vous savez comment utiliser lambda et l'argument "key", une solution simple est:
max_index = max( range( len(my_list) ), key = lambda index : my_list[ index ] )
Utilise un tableau numpy et la fonction argmax ()
a=np.array([1,2,3])
b=np.argmax(a)
print(b) #2
Je pense que la réponse ci-dessus résout votre problème, mais je pensais partager une méthode qui vous donne le minimum et tous les indices dans lesquels le minimum apparaît.
minval = min(mylist)
ind = [i for i, v in enumerate(mylist) if v == minval]
Cela passe la liste deux fois mais est encore assez rapide. Il est cependant légèrement plus lent que de trouver l'indice de la première rencontre de la minimale. Donc, si vous avez besoin d'un seul des minima, utilisez la solution de Matt Anderson , Si vous en avez tous besoin, utilisez ceci.
Pourquoi prendre la peine d'ajouter d'abord des indices, puis de les Inverser? La fonction Enumerate() est juste un cas particulier d'utilisation de la fonction zip (). Utilisons-le de manière appropriée:
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)
Dites que vous avez une liste telle que:
a = [9,8,7]
Les deux méthodes suivantes sont des moyens assez compacts pour obtenir un tuple avec l'élément minimum et son index. Les deux prennent un similaire temps à traiter. J'aime mieux la méthode zip, mais c'est mon goût.
Méthode 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)
Énumérer méthode
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)
Après avoir obtenu les valeurs maximales, essayez ceci:
max_val = max(list)
index_max = list.index(max_val)
Beaucoup plus simple que beaucoup d'options.
Juste un ajout mineur à ce qui a déjà été dit.
values.index(min(values))
semble renvoyer le plus petit indice de min. Ce qui suit obtient le plus grand index:
values.reverse()
(values.index(min(values)) + len(values) - 1) % len(values)
values.reverse()
La dernière ligne peut être laissée de côté si l'effet secondaire de l'inversion en place n'a pas d'importance.
Pour parcourir toutes les occurrences
indices = []
i = -1
for _ in range(values.count(min(values))):
i = values[i + 1:].index(min(values)) + i + 1
indices.append(i)
Par souci de brièveté. C'est probablement une meilleure idée de cache min(values), values.count(min)
en dehors de la boucle.
Un moyen simple de trouver les index avec une valeur minimale dans une liste si vous ne voulez pas importer de modules supplémentaires:
min_value = min(values)
indexes_with_min_value = [i for i in range(0,len(values)) if values[i] == min_value]
, Puis choisissez par exemple le premier:
choosen = indexes_with_min_value[0]
Aussi Simple que cela:
stuff = [2, 4, 8, 15, 11]
index = stuff.index(max(stuff))
Ne pas avoir un représentant assez élevé pour commenter la réponse existante.
, Mais pour https://stackoverflow.com/a/11825864/3920439 réponse
Cela fonctionne pour les entiers, mais ne fonctionne pas pour le tableau de flotteurs (au moins en Python 3.6)
Il va soulever TypeError: list indices must be integers or slices, not float
Https://docs.python.org/3/library/functions.html#max
Si plusieurs éléments sont maximaux, la fonction renvoie le premier rencontré. Ceci est compatible avec d'autres outils de préservation de la stabilité de tri tels que sorted(iterable, key=keyfunc, reverse=True)[0]
Pour obtenir plus que le premier, utilisez la méthode de tri.
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)]