Abrufen des Index des zurückgegebenen max- oder min-Elements mit max () / min () in einer Liste

465

Ich verwende Pythons maxund minFunktionen in Listen für einen Minimax-Algorithmus und benötige den Index des von max()oder zurückgegebenen Werts min(). Mit anderen Worten, ich muss wissen, welcher Zug den Maximalwert (beim Zug eines ersten Spielers) oder den Minimalwert (beim zweiten Spieler) ergab.

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)

Ich muss in der Lage sein, den tatsächlichen Index des Min- oder Max-Werts zurückzugeben, nicht nur den Wert.

Kevin Griffin
quelle
32
Das eingebaute divmodexistiert, um zu verhindern, dass man [i / 3, i % 3]viel sagen muss .
Mike Graham

Antworten:

416
if isMinLevel:
    Rückgabewerte.index (min (Werte))
sonst:
    Rückgabewerte.index (max (Werte))
zu viel php
quelle
38
@ KevinGriffin, Beachten Sie, dass Sie dadurch nur eines von möglicherweise mehreren Vorkommen des Minimums / Maximums erhalten. Dies ist möglicherweise nicht das, was Sie möchten, zum Beispiel, wenn es möglich ist, Ihren Gewinn auf die gleiche Weise zu erhöhen, aber einer von ihnen verletzt den anderen Spieler mehr. Ich weiß nicht, ob dies ein Fall ist, den Sie berücksichtigen müssen.
Mike Graham
89
@ Kashyap Es ist eigentlich O (N), nicht O (N ^ 2). Im min-Fall wird zuerst min (Werte) ausgewertet, was O (N) ist, dann wird values.index () aufgerufen, was auch O (N) ist. O (N) + O (N) = O (N). Das zu indizierende Argument wird nur einmal ausgewertet. Es ist gleichbedeutend mit:tmp = min(values); return values.index(tmp)
Tom Karzes
@ zu viel PHP, was zu tun ist, wenn sich Elemente wiederholen.
Shashi Tunga
@ShashiTunga [list] .index () gibt nur das erste Auftreten von etwas zurück. Es kann nicht garantiert werden, dass es exklusiv ist. Der Mindestwert ist möglicherweise nicht eindeutig in der Liste
Scott Anderson
472

Angenommen, Sie haben eine Liste values = [3,6,1,5]und benötigen den Index des kleinsten Elements, dh index_min = 2in diesem Fall.

Vermeiden Sie die itemgetter()in den anderen Antworten dargestellte Lösung und verwenden Sie sie stattdessen

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

weil es weder benötigt import operatornoch verwendet werden enumeratemuss und immer schneller ist (Benchmark unten) als eine Lösung, die verwendet wird itemgetter().

Wenn Sie mit Numpy-Arrays zu tun haben oder es sich numpyals Abhängigkeit leisten können , sollten Sie auch die Verwendung in Betracht ziehen

import numpy as np
index_min = np.argmin(values)

Dies ist schneller als die erste Lösung, selbst wenn Sie sie auf eine reine Python-Liste anwenden, wenn:

  • es ist größer als ein paar Elemente (ungefähr 2 ** 4 Elemente auf meiner Maschine)
  • Sie können sich die Speicherkopie von einer reinen Liste in ein numpyArray leisten

wie dieser Benchmark zeigt: Geben Sie hier die Bildbeschreibung ein

Ich habe den Benchmark auf meinem Computer mit Python 2.7 für die beiden oben genannten Lösungen (blau: reines Python, erste Lösung) (rot, numpy-Lösung) und für die Standardlösung basierend auf itemgetter()(schwarz, Referenzlösung) ausgeführt. Der gleiche Benchmark mit Python 3.5 zeigte, dass die Methoden genau den gleichen wie der oben vorgestellte Fall von Python 2.7 vergleichen

gg349
quelle
Eine sehr starke +1. Ich mag das Benchmarking der vorgeschlagenen Lösungen und die Faustregeln, die Sie zusammengefasst haben. Können Sie, wie ich in einer anderen Antwort unten vorgeschlagen habe, Ihren Testcode bereitstellen (oder einen Link dazu erstellen), damit andere Ihre Ergebnisse reproduzieren können? Maschinen und Bibliotheken ändern sich im Laufe der Zeit und ermöglichen den Vergleich mit anderen Lösungen.
Rakurai
3
Ich denke, es könnte einen Tippfehler geben: xrange. Sollte es nicht Reichweite sein?
Lindsay Fowler
6
@ LindsayFowler xrange()ist jetzt veraltet, können Sie verwendenrange()
David
np.argmin funktioniert nicht für Floats. Nur der erste Vorschlag funktioniert mit Ints und Floats.
Jimh
Ich denke, Sie irren sich, versuchen Sie es import numpy as np; x = [2.3, -1.4]; np.argmin(x). Sie werden sehen, dass dies auch argminauf Schwimmern funktioniert
gg349
332

Sie können den Min / Max-Index und den Wert gleichzeitig finden, wenn Sie die Elemente in der Liste auflisten, aber Min / Max für die ursprünglichen Werte der Liste ausführen. Wie so:

import operator
min_index, min_value = min(enumerate(values), key=operator.itemgetter(1))
max_index, max_value = max(enumerate(values), key=operator.itemgetter(1))

Auf diese Weise wird die Liste nur einmal für min (oder max) durchlaufen.

Matt Anderson
quelle
110
Oder verwenden Sie ein Lambda:key=lambda p: p[1]
Scry
116

Wenn Sie den Index von max in einer Liste von Zahlen finden möchten (was Ihr Fall zu sein scheint), empfehle ich Ihnen, numpy zu verwenden:

import numpy as np
ind = np.argmax(mylist)
dr.haz
quelle
Bei mehrfachem Auftreten der Maximalwerte werden die dem ersten Auftreten entsprechenden Indizes zurückgegeben.
Cohensius
41

Möglicherweise wäre eine einfachere Lösung, das Array von Werten in ein Array von Werten, Indexpaaren, umzuwandeln und das Maximum / Min davon zu nehmen. Dies würde den größten / kleinsten Index ergeben, der das Maximum / Min hat (dh Paare werden verglichen, indem zuerst das erste Element verglichen wird und dann das zweite Element verglichen wird, wenn die ersten gleich sind). Beachten Sie, dass es nicht erforderlich ist, das Array tatsächlich zu erstellen, da Min / Max Generatoren als Eingabe zulassen.

values = [3,4,5]
(m,i) = max((v,i) for i,v in enumerate(values))
print (m,i) #(5, 2)
Ant6n
quelle
30
list=[1.1412, 4.3453, 5.8709, 0.1314]
list.index(min(list))

Gibt Ihnen den ersten Index des Minimums.

Andy
quelle
18

Ich denke, das Beste, was Sie tun können, ist, die Liste in a zu konvertieren numpy arrayund diese Funktion zu verwenden:

a = np.array(list)
idx = np.argmax(a)
Akshaya Natarajan
quelle
14

Ich war auch daran interessiert und verglich einige der vorgeschlagenen Lösungen mit perfplot (einem meiner Lieblingsprojekte ).

Es stellt sich heraus, dass der Nummel Argmin ist ,

numpy.argmin(x)

ist die schnellste Methode für ausreichend große Listen, selbst bei der impliziten Konvertierung von der Eingabe listin a numpy.array.

Geben Sie hier die Bildbeschreibung ein


Code zum Generieren des Plots:

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,
    )
Nico Schlömer
quelle
Beachten Sie, dass die gleiche Schlussfolgerung bereits oben in meiner Antwort vor mehr als 2 Jahren veröffentlicht wurde und mehr Informationen darüber enthält, wann und warum Argmin verwendet werden kann oder nicht. Ziehen Sie in Betracht, die Antwort zu löschen, was auch dem, was bereits auf derselben Seite vorgeschlagen wurde, keinen Wert verleiht. Überprüfen Sie auch Ihre anderen Antworten auf SO auf ein ähnliches Verhalten: Sie scheinen die tatsächliche Antwort nicht zu zitieren, die die beste Lösung für Ihre Leistungsanalysen darstellt. Dies ist ziemlich schlecht, insbesondere für jemanden mit> 10.000 Wiederholungen, der lange genug da war, um es besser zu wissen.
gg349
@ gg349, sehr gute Punkte, aber er liefert den Quellcode zum Generieren der Ergebnisse, wodurch dieser leicht reproduzierbar und anpassbar ist, um andere Lösungen zu vergleichen. Ich bin damit einverstanden, dass er erwägt, diese Antwort als Duplikat zu entfernen, aber vielleicht können Sie Ihrer Antwort einen Mehrwert verleihen, indem Sie den von Ihnen verwendeten Code einfügen oder mit ihm verknüpfen?
Rakurai
8

Verwenden Sie ein Numpy-Array und die Funktion argmax ()

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

Versuchen Sie Folgendes, nachdem Sie die Maximalwerte erhalten haben:

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

Viel einfacher als viele Optionen.

alpha_989
quelle
6

Ich denke, die obige Antwort löst Ihr Problem, aber ich dachte, ich würde eine Methode teilen, die Ihnen das Minimum und alle Indizes gibt, in denen das Minimum erscheint.

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

Dies passiert die Liste zweimal, ist aber immer noch ziemlich schnell. Es ist jedoch etwas langsamer als das Finden des Index der ersten Begegnung des Minimums. Wenn Sie also nur eines der Minima benötigen, verwenden Sie die Lösung von Matt Anderson . Wenn Sie alle benötigen, verwenden Sie diese.

Burak Bağdatlı
quelle
1
Ich mag das, weil es Basis-Python verwendet und ich finde das Listenverständnis leichter zu verstehen als Itemgetter, Lambda usw. (und flexibel genug, um eine Vielzahl von Aufgaben zu lösen, wie diese ...)
James
roh. Ich bevorzuge das.
Dev_Man
6

Verwenden Sie die Funktion numpy.where des Numpy-Moduls

import numpy as n
x = n.array((3,3,4,7,4,56,65,1))

Für den Index des Mindestwerts:

idx = n.where(x==x.min())[0]

Für den Index des Maximalwerts:

idx = n.where(x==x.max())[0]

In der Tat ist diese Funktion viel leistungsfähiger. Sie können alle Arten von Booleschen Operationen ausführen. Für einen Wertindex zwischen 3 und 60:

idx = n.where((x>3)&(x<60))[0]
idx
array([2, 3, 4, 5])
x[idx]
array([ 4,  7,  4, 56])
Ishan Tomar
quelle
Der Index in Python beginnt bei 0. Der zurückgegebene Index muss 6 (für 65) sein, während Ihr Code 7 zurückgibt (OPs Frage lautete "Getting the index ...")
Tagoma
Im Befehl habe ich nach dem Index des Minimalwerts (hier: 1) abgefragt, dessen Index IS 7 ist. 65 ist der Maximalwert der Elemente im Array. Wenn Sie Folgendes eingeben: n.where (x == x.max ()) [0], erhalten Sie einen Index von max. Wert, der hier 65 ist. Sein Index wird 6 sein
Ishan Tomar
Verwendung von Numpy: wahrscheinlich in dieser Anwendung verboten. Aber wenn Sie Numpy verwenden, ist es viel besser, nur das zu verwenden, argmin()was Sie hier getan haben.
RBF06
Danke @ RBF06 Ich werde es überprüfen.
Ishan Tomar
5

Dies ist einfach möglich mit dem eingebauten in enumerate()und max()Funktion und das optionale keyArgument der max()Funktion und einen einfachen Lambda - Ausdruck:

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

In den Dokumenten max()heißt es, dass das keyArgument eine Funktion wie in der list.sort()Funktion erwartet . Siehe auch Sortieren .

Es funktioniert genauso für min(). Übrigens gibt es den ersten Max / Min-Wert zurück.

Simon Hänisch
quelle
Späte aber beste Antwort (wenn Sie keine Geschwindigkeit brauchen).
mmj
5

Angenommen, Sie haben eine Liste wie:

a = [9,8,7]

Die folgenden zwei Methoden sind ziemlich kompakte Methoden, um ein Tupel mit dem minimalen Element und seinem Index zu erhalten. Beide nehmen eine ähnliche Bearbeitungszeit. Ich mag die Zip-Methode besser, aber das ist mein Geschmack.

Zip-Methode

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)

Methode aufzählen

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

Solange Sie wissen, wie man Lambda und das "Schlüssel" -Argument verwendet, ist eine einfache Lösung:

max_index = max( range( len(my_list) ), key = lambda index : my_list[ index ] )
Veiga
quelle
Sehr sauber! Und im Gegensatz zu der akzeptierten Antwort ist dies wahres O (n), richtig? Ich weiß, dass O (2n) als O (n) betrachtet wird, aber bei sehr großen nkann es merklich langsamer sein.
Kevlarr
4

So einfach ist das :

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

index = stuff.index(max(stuff))
dctremblay
quelle
3

Warum zuerst Indizes hinzufügen und dann umkehren? Die Funktion Enumerate () ist nur ein Sonderfall der Verwendung der Funktion zip (). Lassen Sie es uns angemessen verwenden:

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)
Sophist
quelle
2

Nur eine kleine Ergänzung zu dem, was bereits gesagt wurde. values.index(min(values))scheint den kleinsten Index von min zurückzugeben. Folgendes erhält den größten Index:

    values.reverse()
    (values.index(min(values)) + len(values) - 1) % len(values)
    values.reverse()

Die letzte Zeile kann weggelassen werden, wenn der Nebeneffekt der Umkehrung keine Rolle spielt.

Durch alle Vorkommen iterieren

    indices = []
    i = -1
    for _ in range(values.count(min(values))):
      i = values[i + 1:].index(min(values)) + i + 1
      indices.append(i)

Um es kurz zu machen. Es ist wahrscheinlich eine bessere Idee, min(values), values.count(min)außerhalb der Schleife zwischenzuspeichern.

hyperbolisch
quelle
2
reversed(…)statt ….reverse()ist wahrscheinlich vorzuziehen, da es nicht mutiert und trotzdem einen Generator zurückgibt. Und alle Vorkommnisse könnten auch seinminv = min(values); indices = [i for i, v in enumerate(values) if v == minv]
HoverHell
2

Eine einfache Möglichkeit, die Indizes mit minimalem Wert in einer Liste zu finden, wenn Sie keine zusätzlichen Module importieren möchten:

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

Dann wählen Sie zum Beispiel den ersten:

choosen = indexes_with_min_value[0]
antoninstuppa
quelle
1

Haben Sie nicht genügend Wiederholungen, um die vorhandene Antwort zu kommentieren.

Aber für https://stackoverflow.com/a/11825864/3920439 antworten

Dies funktioniert für Ganzzahlen, aber nicht für ein Array von Floats (zumindest in Python 3.6). Es wird ausgelöst TypeError: list indices must be integers or slices, not float

ThePianoDentist
quelle
0

https://docs.python.org/3/library/functions.html#max

Wenn mehrere Elemente maximal sind, gibt die Funktion das erste gefundene zurück. Dies steht im Einklang mit anderen Werkzeugen zur Erhaltung der Sortierstabilität, wie zsorted(iterable, key=keyfunc, reverse=True)[0]

Um mehr als nur die ersten zu erhalten, verwenden Sie die Sortiermethode.

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

Was ist damit:

a=[1,55,2,36,35,34,98,0]
max_index=dict(zip(a,range(len(a))))[max(a)]

Es erstellt ein Wörterbuch aus den Elementen in aals Schlüssel und ihren Indizes als Werte und dict(zip(a,range(len(a))))[max(a)]gibt somit den Wert zurück, der dem Schlüssel entspricht, der max(a)der Index des Maximums in a ist. Ich bin ein Anfänger in Python, daher weiß ich nichts über die rechnerische Komplexität dieser Lösung.

Dr. Simplisist
quelle