J'utilise les fonctions max
et min
de Python sur des listes pour un algorithme minimax, et j'ai besoin de l'index de la valeur renvoyée par max()
ou min()
. En d'autres termes, j'ai besoin de savoir quel coup a produit la valeur max (au tour d'un premier joueur) ou min (le 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 être capable de renvoyer l'index réel de la valeur minimale ou maximale, pas seulement la valeur.
si isMinLevel: retourne valeurs.index (min (valeurs)) sinon: retourne valeurs.index (max (valeurs))
Supposons que vous avez une liste values = [3,6,1,5]
et que vous 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 plutôt
index_min = min(xrange(len(values)), key=values.__getitem__)
car il n’a pas besoin de import operator
ni d’utiliser enumerate
, et il est toujours plus rapide (référence ci-dessous) qu’une solution utilisant itemgetter()
.
Si vous utilisez des tableaux numpy ou si vous pouvez vous permettre numpy
comme 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:
numpy
J'ai exécuté le test de performance 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) . Même repère avec Python 3.5 a montré que les méthodes comparent exactement la même chose que dans le cas Python 2.7 présenté ci-dessus
Vous pouvez rechercher l'index et la valeur min/max en même temps si vous énumérez les éléments de la liste, mais effectuez les opérations min/max sur les valeurs d'origine de la liste. Ainsi:
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 pendant min (ou max).
Si vous voulez trouver l'index de max dans une liste de nombres (ce qui semble être votre cas), je vous suggère d'utiliser numpy:
import numpy as np
ind = np.argmax(mylist)
Une solution plus simple consisterait peut-être à transformer le tableau de valeurs en un tableau de valeurs, paires-index, et à prendre le nombre max/min de celui-ci. Cela donnerait le plus grand/le plus petit indice 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 identiques). Notez qu'il n'est pas nécessaire de créer 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.
Cela m’intéressait également et comparais certaines des solutions suggérées avec perfplot (un de mes projets pour animaux de compagnie).
Il 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
en un numpy.array
.
Code pour générer l'intrigue:
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.where
import numpy as n
x = n.array((3,3,4,7,4,56,65,1))
Pour index de valeur minimale:
idx = n.where(x==x.min())[0]
Pour index de valeur maximale:
idx = n.where(x==x.max())[0]
En fait, cette fonction est beaucoup plus puissante. Vous pouvez poser toutes sortes d'opérations booléennes Pour un indice de valeur compris 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])
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.
Utiliser un tableau numpy et la fonction argmax ()
a=np.array([1,2,3])
b=np.argmax(a)
print(b) #2
Ceci est tout simplement possible en utilisant les fonctions intégrées enumerate()
et max()
et l'argument optionnel key
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 documents relatifs à max()
, il est indiqué que l’argument key
attend une fonction similaire à celle de list.sort()
. Voir également le Comment faire pour trier .
Cela fonctionne de la même manière pour min()
. Btw renvoie la première valeur max/min.
Tant que vous savez utiliser lambda et l'argument "clé", une solution simple est:
max_index = max( range( len(my_list) ), key = lambda index : my_list[ index ] )
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 deux fois la liste mais reste assez rapide. Il est cependant légèrement plus lent que de trouver l'indice de la première rencontre du minimum. Donc, si vous avez besoin d’un seul des minima, utilisez la solution de Matt Anderson , si vous en avez besoin, utilisez ceci.
Disons que vous avez une liste telle que:
a = [9,8,7]
Les deux méthodes suivantes sont des méthodes assez compactes pour obtenir un tuple avec l'élément minimum et son index. Les deux prennent un temps similaire à traiter. J'aime mieux la méthode Zip, mais c'est mon goût.
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)
Pourquoi se donner la peine d’ajouter d’abord des indices, puis de les inverser? La fonction Enumerate () n'est qu'un cas particulier de l'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)
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 indice:
values.reverse()
(values.index(min(values)) + len(values) - 1) % len(values)
values.reverse()
La dernière ligne peut être omise 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)
Pour des raisons de brièveté. Il est probablement préférable de mettre en 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 souhaitez 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]
Je pense que la meilleure chose à faire est de convertir la liste en numpy array
et d’utiliser cette fonction:
a = np.array(list)
idx = np.argmax(a)
Aussi simple que cela :
stuff = [2, 4, 8, 15, 11]
index = stuff.index(max(stuff))
Ne pas avoir assez haut représentant pour commenter la réponse existante.
Mais pour https://stackoverflow.com/a/11825864/3920439 answer
Cela fonctionne pour les entiers, mais pas pour les tableaux de flottants (au moins en python 3.6) Cela augmentera 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 préservant 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)]