Obtenir l'index de l'élément max ou min de retour à l'aide max () / min () sur une liste

StackOverflow https://stackoverflow.com/questions/2474015

  •  21-09-2019
  •  | 
  •  

Question

J'utilise max Python et les fonctions min sur les listes pour un algorithme minimax, et je dois l'indice de la valeur retournée par max() ou min(). En d'autres termes, je dois savoir qui a produit le mouvement max (à un premier tour du joueur) ou min (deuxième joueur) valeur.

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 en mesure de retourner l'indice réel de la valeur min ou max, pas seulement la valeur.

Était-ce utile?

La solution

if isMinLevel:
    return values.index(min(values))
else:
    return values.index(max(values))

Autres conseils

Dites que vous avez une liste values = [3,6,1,5], et ont besoin de l'indice de l'élément le plus petit, à savoir index_min = 2 dans ce cas.

Contournez la solution avec itemgetter() présentée dans les autres réponses, et utiliser à la place

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

car il ne nécessite pas import operator ni à utiliser enumerate, et il est toujours plus rapide (référence ci-dessous) qu'une solution en utilisant itemgetter().

Si vous traitez avec des tableaux de numpy ou peut se permettre numpy comme une dépendance, Pensez également à 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 pure Python si:

  • il est plus grand que quelques éléments (environ 2 ** 4 éléments sur ma machine)
  • vous pouvez vous permettre la copie de la mémoire à partir d'une liste pure un tableau de numpy

comme cette référence souligne: entrer image description ici «  loading=

J'ai couru la référence 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 indice de référence avec Python 3.5 a montré que les méthodes comparent exactement le même du python 2.7 cas présenté ci-dessus

Vous pouvez trouver le min / max indice et la valeur en même temps si vous énumérez les éléments de la liste, mais effectuer min / max sur les valeurs d'origine de la liste. Comme ceci:

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 parcouru une fois pour min (ou max).

Si vous voulez trouver l'index de max dans une liste de nombres (ce qui semble votre cas), alors je vous suggère d'utiliser numpy:

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

Peut-être une solution simple consisterait à transformer le tableau de valeurs en un tableau de valeur, des paires d'index, et prendre le max / min de cela. Cela donnerait l'indice le plus grand / le plus petit qui a le max / min (à savoir des paires sont comparés en comparant d'abord le premier élément, et en comparant ensuite le second élément si les premiers sont les mêmes). Notez qu'il est pas nécessaire de créer réellement le tableau, car min / max permet générateurs comme 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 premier indice de minimum.

Je suis aussi intéressé par cela et comparé certaines des solutions proposées en utilisant perfplot (un projet animal de compagnie le mien).

numpy de la argmin ,

numpy.argmin(x)

est la méthode la plus rapide pour les listes assez grandes, même avec la conversion implicite de la list d'entrée à un numpy.array.

 ici


Code pour générer le terrain:

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

A l'aide d'un réseau de numpy et la fonction argmax ()

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

Une fois que vous obtenez les valeurs maximales, essayez ceci:

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

Beaucoup plus simple que beaucoup d'options.

Je pense que la meilleure chose à faire est de convertir la liste à un numpy array et utilisez cette fonction:

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

Je pense que la réponse résout votre problème ci-dessus mais je pensais que je partagerais une méthode qui vous donne le minimum et tous les indices minimum apparaît dans.

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

passe la liste deux fois, mais est encore assez rapide. Il est cependant un peu plus lent que de trouver l'indice de la première rencontre du minimum. Donc, si vous avez juste besoin de l'un des minima, utilisez la solution de Matt Anderson , si vous en avez besoin, utilisez ceci.

Fonction Utiliser le module numpy de numpy.where

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

Il est simplement possible d'utiliser la fonction enumerate() et max() intégré et l'argument optionnel key de la fonction max() et une simple expression lambda:

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

Dans la documentation pour max() il est dit que l'argument key attend une fonction comme dans la fonction list.sort() . Voir aussi le Tri Comment .

Il fonctionne de la même chose pour min(). BTW elle retourne la première valeur de max / min.

Tant que vous savez comment utiliser lambda et l'argument « clé », une solution simple est:

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

Disons que vous avez une liste, tels que:

a = [9,8,7]

Les deux méthodes suivantes sont des moyens assez compactes pour obtenir un tuple avec l'élément minimum et son indice. Les deux prennent un similaire de temps pour traiter. Je ferais mieux comme 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)

méthode énumérer

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 prendre la peine d'ajouter des indices d'abord, puis les inverser? fonction Énumérer () est un cas particulier de l'utilisation de la fonction zip (). Utilisons de manière correspond le:

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)

Juste un petit ajout à ce qui a déjà été dit. values.index(min(values)) semble retourner 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 omis si l'effet secondaire de renverser en place n'a pas d'importance.

Pour itérer 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 concision. Il est probablement une meilleure idée de mettre en cache min(values), values.count(min) en dehors de la boucle.

Une façon simple pour trouver les indices ayant une valeur minimale dans une liste si vous ne souhaitez pas importer des modules supplémentaires:

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

Ensuite, choisissez par exemple le premier:

choosen = indexes_with_min_value[0]

Aussi simple que ça:

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

index = stuff.index(max(stuff))

Ne pas avoir assez haut représentant pour commenter la réponse existante.

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 soulèvera 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 retourne la première rencontrée. Ceci est cohérent avec d'autres outils de conservation tri stabilité tels que sorted(iterable, key=keyfunc, reverse=True)[0]

Pour obtenir plus que la première utilisation de 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)]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top