web-dev-qa-db-fra.com

Obtenir l'index de l'item max ou min retourné en utilisant max ()/min () sur une liste

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.

315
Kevin Griffin
 si isMinLevel: 
 retourne valeurs.index (min (valeurs)) 
 sinon: 
 retourne valeurs.index (max (valeurs)) 
268
too much php

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:

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

comme l'indique ce repère:  enter image description here

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

351
gg349

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

303
Matt Anderson

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)
99
dr.haz

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)
33
Ant6n
list=[1.1412, 4.3453, 5.8709, 0.1314]
list.index(min(list))

Vous donnera le premier index du minimum.

22
Andy

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.

 enter image description here


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,
    )
9
Nico Schlömer

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])
6
Ishan Tomar

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.

5
alpha_989

Utiliser un tableau numpy et la fonction argmax ()

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

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.

4
Simon Hänisch

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

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.

4
Burak Bağdatlı

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.

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 d'énumération

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)
4
Pablo MPA

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)
3
sophist

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.

2
hyperbolic

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]
2
antoninstuppa

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)
1
Akshaya Natarajan

Aussi simple que cela :

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

index = stuff.index(max(stuff))
1
dctremblay

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

1
user3920439

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)]
0
The Demz