Façon pythonique de trouver la valeur maximale et son index dans une liste?

151

Si je veux la valeur maximale dans une liste, je peux simplement écrire max(List), mais que faire si j'ai également besoin de l'index de la valeur maximale?

Je peux écrire quelque chose comme ça:

maximum=0
for i,value in enumerate(List):
    if value>maximum:
        maximum=value
        index=i

Mais cela me semble fastidieux.

Et si j'écris:

List.index(max(List))

Ensuite, il itérera la liste deux fois.

Y a-t-il un meilleur moyen?

Ensoleillé88
la source
Que voulez-vous dire par "il passera la liste deux fois"? List.index (max (List)) fonctionne pour moi.
mwcz
14
@mwc: il itérera une fois la liste pour déterminer la valeur maximale, puis l'itérera une seconde fois pour trouver l'index de cette valeur.
10
List.index () ne serait-il pas problématique s'il y a des valeurs maximales dupliquées?
Logan Yang
@LoganYang oui, il pourrait y avoir deux éléments avec la même valeur.
Florian
Si l'ordre n'est pas important, vous pouvez faire quelque chose comme List.sort () [- 1]
Florian

Réponses:

186

Il existe de nombreuses options, par exemple:

import operator
index, value = max(enumerate(my_list), key=operator.itemgetter(1))
Sven Marnach
la source
2
Ah, j'ai vu cela dans d'autres endroits, mais je pensais qu'il ne renverrait qu'une seule valeur, pas un tuple.
Sunny88
1
@ Sunny88: la keyfonction sert uniquement à décider quel élément est maximal. Les éléments ne sont pas modifiés.
Sven Marnach
6
@SvenMarnach Pourquoi pas à la key=lambda e: e[1]place et éviter ainsi l'importation?
lifebalance
8
@lifebalance L'utilisation itemgetter()est plus rapide, et éviter une importation n'est pas un objectif à poursuivre. Éviter les dépendances externes peut être utile dans certains cas, mais une importation depuis la bibliothèque standard n'est pas un problème.
Sven Marnach
324

Je pense que la réponse acceptée est excellente, mais pourquoi ne le faites-vous pas explicitement? Je pense que plus de gens comprendraient votre code, et c'est en accord avec PEP 8:

max_value = max(my_list)
max_index = my_list.index(max_value)

Cette méthode est également environ trois fois plus rapide que la réponse acceptée:

import random
from datetime import datetime
import operator

def explicit(l):
    max_val = max(l)
    max_idx = l.index(max_val)
    return max_idx, max_val

def implicit(l):
    max_idx, max_val = max(enumerate(l), key=operator.itemgetter(1))
    return max_idx, max_val

if __name__ == "__main__":
    from timeit import Timer
    t = Timer("explicit(l)", "from __main__ import explicit, implicit; "
          "import random; import operator;"
          "l = [random.random() for _ in xrange(100)]")
    print "Explicit: %.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

    t = Timer("implicit(l)", "from __main__ import explicit, implicit; "
          "import random; import operator;"
          "l = [random.random() for _ in xrange(100)]")
    print "Implicit: %.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

Résultats au fur et à mesure qu'ils s'exécutent sur mon ordinateur:

Explicit: 8.07 usec/pass
Implicit: 22.86 usec/pass

Autre ensemble:

Explicit: 6.80 usec/pass
Implicit: 19.01 usec/pass
Escualo
la source
3
Je ne m'attendais pas à ce que ce soit plus rapide. C'est plus rapide même si je remplace l par "l = [random.random () for _ in xrange (10000000)] + [2]", ce qui garantit que le dernier élément est le plus grand.
Sunny88
14
@ Sunny88: Pour une simple liste de nombres, l'approche simple est plus rapide. Si vous recherchez des performances dans ce cas, je vous suggère d'utiliser numpy.argmax(), ce qui est encore 30 fois plus rapide sur ma machine. Si la liste contient des objets plus compliqués que de simples chiffres, l'approche de ma réponse peut devenir plus rapide. Un autre avantage de cette approche est qu'elle peut être utilisée pour des itérateurs arbitraires, pas seulement pour des listes.
Sven Marnach
@ Sven-Marnach Est-ce que numpy serait plus rapide, si je devais d'abord convertir ma liste en un tableau numpy? Serait-ce plus rapide pour l'exemple simple [0,1,0]?
tommy.carstensen
1
@ Sven-Marnach Je viens de vérifier. numpy.argmax est de loin la méthode la plus lente, et elle donne la mauvaise réponse, si le tableau contient des chaînes au lieu de flottants ou d'entiers.
tommy.carstensen
9
List.index () ne serait-il pas problématique s'il y a des valeurs maximales dupliquées?
Logan Yang
20

Cette réponse est 33 fois plus rapide que @Escualo en supposant que la liste est très grande et en supposant qu'il s'agit déjà d'un np.array (). J'ai dû baisser le nombre de tests car le test porte sur 10000000 éléments et pas seulement 100.

import random
from datetime import datetime
import operator
import numpy as np

def explicit(l):
    max_val = max(l)
    max_idx = l.index(max_val)
    return max_idx, max_val

def implicit(l):
    max_idx, max_val = max(enumerate(l), key=operator.itemgetter(1))
    return max_idx, max_val

def npmax(l):
    max_idx = np.argmax(l)
    max_val = l[max_idx]
    return (max_idx, max_val)

if __name__ == "__main__":
    from timeit import Timer

t = Timer("npmax(l)", "from __main__ import explicit, implicit, npmax; "
      "import random; import operator; import numpy as np;"
      "l = np.array([random.random() for _ in xrange(10000000)])")
print "Npmax: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

t = Timer("explicit(l)", "from __main__ import explicit, implicit; "
      "import random; import operator;"
      "l = [random.random() for _ in xrange(10000000)]")
print "Explicit: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

t = Timer("implicit(l)", "from __main__ import explicit, implicit; "
      "import random; import operator;"
      "l = [random.random() for _ in xrange(10000000)]")
print "Implicit: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

Résultats sur mon ordinateur:

Npmax: 8.78 msec/pass
Explicit: 290.01 msec/pass
Implicit: 790.27 msec/pass
portforwardpodcast
la source
Juste pour clarifier: l'accélération est simplement due à l'implémentation numpy C par rapport au python pur? Ou il existe un moyen d'améliorer la réponse de @ Escualo en utilisant du python pur?
max
Si l'on souhaite utiliser python 3.6, on peut faire quelque chose comme: "l = np.array ([random.random () for _ in range (10000000)])") print (f "Npmax: {(1000 * t. timeit (number = 10) / 10): 5.2f} msec / pass ")
Piotr Siejda
C'était le 2.7
portforwardpodcast
1
Eh bien, la vitesse de numpy.argmaxsemble incroyable jusqu'à ce que vous le laissiez traiter une liste Python standard . Ensuite, la vitesse se situe entre la version explicite et implicite. Je suppose que np.arraycela ne crée pas seulement une liste, mais cela enregistre des informations supplémentaires - comme par exemple les valeurs min et max (juste une hypothèse).
Miroslaw Opoka
18

Avec la bibliothèque intégrée de Python, c'est assez simple:

a = [2, 9, -10, 5, 18, 9] 
max(xrange(len(a)), key = lambda x: a[x])

Cela indique maxde trouver le plus grand nombre dans la liste [0, 1, 2, ..., len(a)], en utilisant la fonction personnalisée lambda x: a[x], qui dit que 0c'est en fait 2, 1est en fait 9, etc.

Sunil Kapil
la source
Dans Python 3, il n'y a pas de xrange, si vous voulez écrire du code qui s'exécutera à la fois pour Python 2 et Python 3, vous devez utiliser range ().
Chunde Huang
10
max([(v,i) for i,v in enumerate(my_list)])
Luis Sobrecueva
la source
C'est mieux car vous pouvez l'adapter pour l'utiliser avec autre chose que tuple.
wieczorek1990
Comment ça marche exactement? Pouvez-vous décomposer le processus?
clabe45
Salut @ clabe45, il convertit ma_liste en une liste de tuples (v, i) où v est chaque élément de ma liste et i est l'index correspondant, puis il obtient le tuple avec la valeur maximale (et avec son index associé aussi)
Luis Sobrecueva
4
Merci, pouvez-vous poster cela dans la réponse éventuellement? Et comment maxsavoir prendre en compte le premier élément de chaque tuple ( v) lors du calcul de la valeur maximale?
clabe45
1
@ clabe45 Peut-être que cette réponse arrive trop tard, mais pour d'autres (comme moi) qui sont tombés sur ce fil maintenant, ici: stackoverflow.com/questions/18296755/... est une explication. Pas cette ligne: "Par défaut, max comparera les éléments par le premier index, si le premier index est le même, alors il comparera le deuxième index." Alors je l'ai essayé avec list: l = [1,1,1] puis max ([(v, i) for i, v in enumerate (l)]) et ça ne me donne pas le premier mais le dernier un: (1,2) comme résultat. J'espère que cela explique :)
Anupam Jain
10

Je suggérerais un moyen très simple:

import numpy as np
l = [10, 22, 8, 8, 11]
print(np.argmax(l))
print(np.argmin(l))

J'espère que ça aide.

Igor Manzhos
la source
4
max([(value,index) for index,value in enumerate(your_list)]) #if maximum value is present more than once in your list then this will return index of the last occurrence

Si la valeur maximale est présente plusieurs fois et que vous souhaitez obtenir tous les indices,

max_value = max(your_list)
maxIndexList = [index for index,value in enumerate(your_list) if value==max(your_list)]
Islam Taohidul
la source
1
Ouaip. J'ai presque posté une réponse, mais j'ai vu que vous aviez déjà la même solution avec la même logique dans votre liste de compréhension en une ligne.
WalyKu
2

Peut-être avez-vous besoin d'une liste triée de toute façon?

Essaye ça:

your_list = [13, 352, 2553, 0.5, 89, 0.4]
sorted_list = sorted(your_list)
index_of_higher_value = your_list.index(sorted_list[-1])
Mattias
la source
1. Le tri a une complexité temporelle plus élevée. 2. sorted_listn'a pas d'index mais des valeurs, donc cela ne fonctionnerait pas.
1

désolé d'avoir relancé ce fil, mais j'ai pensé que ma méthode valait la peine d'être ajoutée.

Le nom de la liste dans cet exemple 'list'

list.sort()
print(list[-1])

Cela imprimera facilement la valeur la plus élevée de la liste!

list.sort()trie la liste en fonction de la valeur de l'élément dans la table ASCII , donc trie efficacement la liste du plus bas au plus élevé. J'imprime ensuite simplement la dernière valeur de la liste (qui sera le plus grand nombre) en utilisant print(list[-1]).

J'espère que cela t'aides!

Mackey Johnstone
la source
5
nous ne pouvons pas obtenir l'index de cette façon
toing_toing
-1

Voici une solution complète à votre question en utilisant les fonctions intégrées de Python:

# Create the List
numbers = input("Enter the elements of the list. Separate each value with a comma. Do not put a comma at the end.\n").split(",") 

# Convert the elements in the list (treated as strings) to integers
numberL = [int(element) for element in numbers] 

# Loop through the list with a for-loop

for elements in numberL:
    maxEle = max(numberL)
    indexMax = numberL.index(maxEle)

print(maxEle)
print(indexMax)
Samdom pour la paix
la source