Pythonischer Weg, um den Maximalwert und seinen Index in einer Liste zu finden?

151

Wenn ich den Maximalwert in einer Liste haben möchte, kann ich einfach schreiben max(List), aber was ist, wenn ich auch den Index des Maximalwerts benötige?

Ich kann so etwas schreiben:

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

Aber es sieht für mich langweilig aus.

Und wenn ich schreibe:

List.index(max(List))

Dann wird die Liste zweimal wiederholt.

Gibt es einen besseren Weg?

Sunny88
quelle
Was meinst du mit "es wird die Liste zweimal bestehen"? List.index (max (List)) funktioniert bei mir.
MWCZ
14
@mwc: Die Liste wird einmal durchlaufen, um den Maximalwert zu bestimmen, und dann ein zweites Mal, um den Index dieses Werts zu finden.
10
Wäre list.index () nicht problematisch, wenn doppelte Maximalwerte vorhanden wären?
Logan Yang
@LoganYang ja, es könnten zwei Artikel mit demselben Wert sein.
Florian
Wenn der Auftrag nicht wichtig ist, könnten Sie so etwas wie List.Sort tun () [- 1]
Florian

Antworten:

186

Es gibt viele Möglichkeiten, zum Beispiel:

import operator
index, value = max(enumerate(my_list), key=operator.itemgetter(1))
Sven Marnach
quelle
2
Ah, ich habe dies an anderen Orten gesehen, aber ich dachte, dass es nur einen Wert zurückgeben wird, kein Tupel.
Sunny88
1
@ Sunny88: Die keyFunktion wird nur verwendet, um zu entscheiden, welches Element maximal ist. Die Elemente werden nicht geändert.
Sven Marnach
6
@SvenMarnach Warum nicht key=lambda e: e[1]stattdessen und damit den Import vermeiden?
Lebensbalance
8
@lifebalance Die Verwendung itemgetter()ist schneller und das Vermeiden eines Imports ist kein Ziel, das es wert ist, verfolgt zu werden. Das Vermeiden externer Abhängigkeiten kann sich in einigen Fällen lohnen, ein Import aus der Standardbibliothek ist jedoch kein Problem.
Sven Marnach
323

Ich finde die akzeptierte Antwort großartig, aber warum machst du das nicht explizit? Ich bin der Meinung, dass mehr Menschen Ihren Code verstehen würden, und das stimmt mit PEP 8 überein:

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

Diese Methode ist auch ungefähr dreimal schneller als die akzeptierte Antwort:

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)

Ergebnisse, wie sie auf meinem Computer ausgeführt werden:

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

Anderer Satz:

Explicit: 6.80 usec/pass
Implicit: 19.01 usec/pass
Escualo
quelle
3
Ich hatte nicht erwartet, dass es schneller geht. Es ist schneller, selbst wenn ich l durch "l = [random.random () für _ in xrange (10000000)] + [2]" ersetze, was garantiert, dass das letzte Element das größte ist.
Sunny88
14
@ Sunny88: Für eine einfache Liste von Zahlen ist der einfache Ansatz schneller. Wenn Sie in diesem Fall nach Leistung suchen, würde ich die Verwendung empfehlen numpy.argmax(), die auf meinem Computer weitere 30-mal schneller ist. Wenn die Liste kompliziertere Objekte als bloße Zahlen enthält, kann der Ansatz in meiner Antwort schneller werden. Ein weiterer Vorteil dieses Ansatzes besteht darin, dass er für beliebige Iteratoren verwendet werden kann, nicht nur für Listen.
Sven Marnach
@ Sven-Marnach Wäre numpy schneller, wenn ich meine Liste zuerst in ein numpy-Array konvertieren müsste? Wäre es für das einfache Beispiel [0,1,0] schneller?
Tommy.carstensen
1
@ Sven-Marnach habe ich gerade überprüft. numpy.argmax ist bei weitem die langsamste Methode und gibt die falsche Antwort, wenn das Array Zeichenfolgen anstelle von Gleitkommazahlen oder Ganzzahlen enthält.
Tommy.carstensen
9
Wäre list.index () nicht problematisch, wenn doppelte Maximalwerte vorhanden wären?
Logan Yang
20

Diese Antwort ist 33-mal schneller als @Escualo, vorausgesetzt, die Liste ist sehr groß und es handelt sich bereits um ein np.array (). Ich musste die Anzahl der Testläufe verringern, da der Test 10000000 Elemente betrachtet, nicht nur 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 )

Ergebnisse auf meinem Computer:

Npmax: 8.78 msec/pass
Explicit: 290.01 msec/pass
Implicit: 790.27 msec/pass
portforwardpodcast
quelle
Nur um zu verdeutlichen: Die Beschleunigung ist nur auf die numpy C-Implementierung im Vergleich zu reinem Python zurückzuführen? Oder gibt es eine Möglichkeit, die Antwort von @ Escualo mit reinem Python zu verbessern?
Max
Wenn man Python 3.6 verwenden möchte, kann man Folgendes tun: "l = np.array ([random.random () für _ in range (10000000)])") print (f "Npmax: {(1000 * t). timeit (number = 10) / 10): 5.2f} msec / pass ")
Piotr Siejda
Dies war am 2.7
portforwardpodcast
1
Nun, die Geschwindigkeit von numpy.argmaxsieht erstaunlich aus, bis Sie eine Standard- Python-Liste verarbeiten lassen. Dann liegt die Geschwindigkeit zwischen expliziter und impliziter Version. Ich denke, np.arrayes wird nicht nur eine Liste erstellt, sondern es werden einige zusätzliche Informationen darin gespeichert - wie zum Beispiel Min- und Max-Werte (nur eine Hypothese).
Miroslaw Opoka
17

Mit der in Python integrierten Bibliothek ist es ziemlich einfach:

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

Dies teilt maxdie größte Zahl in der Liste zu finden [0, 1, 2, ..., len(a)], die benutzerdefinierte Funktion lambda x: a[x], die besagt , dass 0tatsächlich ist 2, 1ist eigentlich 9, usw.

Sunil Kapil
quelle
In Python 3 gibt es keinen xrange. Wenn Sie Code schreiben möchten, der sowohl für Python 2 als auch für Python 3 ausgeführt wird, sollten Sie range () verwenden.
Chunde Huang
10
max([(v,i) for i,v in enumerate(my_list)])
Luis Sobrecueva
quelle
Dies ist besser, da Sie es anpassen können, um es mit etwas anderem als Tupel zu verwenden.
wieczorek1990
Wie genau funktioniert das? Können Sie den Prozess abbrechen?
Clabe45
Hi @ clabe45, es konvertiert my_list in eine Liste von Tupeln (v, i), wobei v jedes Element meiner Liste und i der entsprechende Index ist, dann erhält es das Tupel mit dem Maximalwert (und auch mit dem zugehörigen Index)
Luis Sobrecueva
4
Danke, kannst du das möglicherweise in der Antwort posten? Und woher weiß man, maxdass man vbei der Berechnung des Maximalwerts nur das erste Element jedes Tupels ( ) berücksichtigt?
Clabe45
1
@ clabe45 Vielleicht kommt diese Antwort zu spät, aber für andere (wie mich), die jetzt auf diesen Thread gestoßen sind , hier: stackoverflow.com/questions/18296755/… ist eine Erklärung. Nicht diese Zeile: "Standardmäßig vergleicht max die Elemente anhand des ersten Index. Wenn der erste Index identisch ist, wird der zweite Index verglichen." Also habe ich es mit Liste versucht: l = [1,1,1] und dann max ([(v, i) für i, v in Aufzählung (l)]) und es gibt mir nicht die erste 1, sondern die letzte eins: (1,2) als Ergebnis. Ich hoffe es erklärt :)
Anupam Jain
10

Ich würde einen sehr einfachen Weg vorschlagen:

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

Ich hoffe es hilft.

Igor Manzhos
quelle
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

Wenn der Maximalwert mehr als einmal vorhanden ist und Sie alle Indizes erhalten möchten,

max_value = max(your_list)
maxIndexList = [index for index,value in enumerate(your_list) if value==max(your_list)]
Taohidul Islam
quelle
1
Jep. Ich hätte fast eine Antwort gepostet, aber dann sah ich, dass Sie bereits dieselbe Lösung mit derselben Logik in Ihrem Einzeiler für das Listenverständnis hatten.
WalyKu
1

Vielleicht brauchen Sie trotzdem eine sortierte Liste?

Versuche dies:

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
quelle
1. Das Sortieren hat eine höhere zeitliche Komplexität. 2. sorted_listhat keine Indizes, aber Werte, also würde es nicht funktionieren.
Zardav
1

Es tut mir leid, dass ich diesen Thread wiederbelebt habe, aber ich dachte, meine Methode wäre es wert, hinzugefügt zu werden.

Der Listenname in diesem Beispiel 'Liste'

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

Damit wird der höchste Wert in der Liste einfach so gedruckt!

list.sort()Sortiert die Liste nach dem Wert des Elements in der ASCII-Tabelle , sodass die Liste effektiv vom niedrigsten zum höchsten Wert sortiert wird. Ich drucke dann einfach den letzten Wert in der Liste (der die größte Zahl sein wird) mit print(list[-1]).

Hoffe das hilft!

Mackey Johnstone
quelle
5
Wir können den Index nicht auf diese Weise erhalten
toing_toing
-1

Hier ist eine vollständige Lösung für Ihre Frage mit den integrierten Funktionen von 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 für den Frieden
quelle