Wie kann ich in Python rückwärts über eine Liste iterieren?
array = [0, 10, 20, 40]
for (i = array.length() - 1; i >= 0; i--)
Wie kann ich in Python rückwärts über eine Liste iterieren?
array = [0, 10, 20, 40]
for (i = array.length() - 1; i >= 0; i--)
>>> xs = [0, 10, 20, 40]
>>> xs[::-1]
[40, 20, 10, 0]
Erweiterte Slice-Syntax wird erklärt aquí . Siehe auch, Dokumentation .
Es gibt drei verschiedene eingebaute Möglichkeiten, eine Liste umzukehren. Welche Methode die beste ist, hängt davon ab, ob Sie es brauchen:
object.reverse()
Methodereversed(object)
der den Iterator erzeugtobject[::-1]
Aus Sicht der Geschwindigkeit ist es am besten, die oben genannten eingebauten Funktionen zu verwenden, um eine Liste umzukehren. Sie sind bei kurzen Listen (10 Elemente) 2 bis 8 Mal schneller und bei langen Listen bis zu 300 Mal schneller als eine manuell erstellte Schleife oder ein Generator. Das macht Sinn - sie sind in einer Muttersprache (z. B. C) geschrieben, werden von Experten erstellt, geprüft und optimiert. Sie sind auch weniger fehleranfällig und können eher mit Rand- und Eckfällen umgehen.
Fügen Sie alle Codeschnipsel in dieser Antwort zusammen, um ein Skript zu erstellen, das die verschiedenen Möglichkeiten der Umkehrung einer Liste, die unten beschrieben werden, ausführt. Es wird jede Methode 100.000 Mal ausführen und dabei die Zeit messen. Die Ergebnisse sind im letzten Abschnitt für Listen der Länge 2, 10 und 1000 Elemente dargestellt.
from timeit import timeit
from copy import copy
def time_str_ms(t):
return '{0:8.2f} ms'.format(t * 1000)
Wenn das Ziel nur darin besteht, die Reihenfolge der Elemente in einer vorhandenen Liste umzukehren, ohne sie in einer Schleife zu bearbeiten oder eine Kopie zu erhalten, verwenden Sie die <list>.reverse()
Funktion. Wenn Sie diese Funktion direkt auf ein Listenobjekt anwenden, wird die Reihenfolge aller Elemente umgekehrt:
Beachten Sie, dass die folgende Funktion die angegebene Originalvariable umkehrt, obwohl sie auch die umgekehrte Liste zurückgibt, d. h. Sie können mit dieser Funktionsausgabe eine Kopie erstellen. Normalerweise würde man dafür keine Funktion erstellen, aber das Timing-Skript erfordert dies.
Wir testen die Leistung dieses Verfahrens auf zwei Arten - zunächst wird eine Liste einfach an Ort und Stelle umgekehrt (die ursprüngliche Liste wird geändert), und dann wird die Liste kopiert und anschließend umgekehrt, um festzustellen, ob dies im Vergleich zu den anderen Verfahren der schnellste Weg zur Erstellung einer umgekehrten Kopie ist.
def rev_in_place(mylist):
mylist.reverse()
return mylist
def rev_copy_reverse(mylist):
a = copy(mylist)
a.reverse()
return a
obj[::-1]
Die eingebaute Index-Slicing-Methode ermöglicht es Ihnen, eine Kopie eines Teils eines beliebigen indizierten Objekts zu erstellen.
Die generische Syntax lautet: <object>[first_index:last_index:step]
. Verwenden Sie die Slicing-Funktion, um eine einfache umgekehrte Liste zu erstellen: <list>[::-1]
. Wenn eine Option leer gelassen wird, werden sie auf die Standardwerte des ersten und letzten Elements des Objekts gesetzt (umgekehrt, wenn die Schrittweite negativ ist).
Die Indizierung ermöglicht die Verwendung negativer Zahlen, die vom Ende des Objektindex rückwärts zählen (d. h. -2 ist das vorletzte Element). Wenn die Schrittweite negativ ist, wird mit dem letzten Element begonnen und um diesen Betrag rückwärts indiziert.
def rev_slice(mylist):
a = mylist[::-1]
return a
reversed(obj)
IteratorfunktionEs gibt eine reversed(indexed_object)
Funktion:
Testen Sie sowohl mit einem rohen Iterator als auch mit der Erstellung einer Liste aus dem Iterator.
def reversed_iterator(mylist):
a = reversed(mylist)
return a
def reversed_with_list(mylist):
a = list(reversed(mylist))
return a
Wie das Timing zeigt, ist es keine gute Idee, eigene Indizierungsmethoden zu entwickeln. Verwenden Sie die eingebauten Methoden, es sei denn, Sie müssen wirklich etwas Eigenes machen. Das bedeutet einfach, dass Sie die eingebauten Methoden lernen müssen.
Bei kleineren Listen ist der Nachteil nicht so groß, aber wenn man die Liste vergrößert, wird der Nachteil gewaltig. Der nachstehende Code könnte sicher optimiert werden, aber er kann niemals mit den eingebauten Methoden mithalten, da diese direkt in einer Muttersprache implementiert sind.
def rev_manual_pos_gen(mylist):
max_index = len(mylist) - 1
return [ mylist[max_index - index] for index in range(len(mylist)) ]
def rev_manual_neg_gen(mylist):
## index is 0 to 9, but we need -1 to -10
return [ mylist[-index-1] for index in range(len(mylist)) ]
def rev_manual_index_loop(mylist):
a = []
reverse_index = len(mylist) - 1
for index in range(len(mylist)):
a.append(mylist[reverse_index - index])
return a
def rev_manual_loop(mylist):
a = []
reverse_index = len(mylist)
for index, _ in enumerate(mylist):
reverse_index -= 1
a.append(mylist[reverse_index])
return a
Nachfolgend finden Sie den Rest des Skripts, um die Zeit für jede Methode der Umkehrung. Es zeigt die Umkehrung an Ort und Stelle mit obj.reverse()
und die Erstellung der reversed(obj)
Iterator sind immer am schnellsten, während die Verwendung von Slices der schnellste Weg ist, eine Kopie zu erstellen.
Es beweist auch, dass man nicht versuchen sollte, einen eigenen Weg zu finden, wenn man nicht muss!
loops_to_test = 100000
number_of_items = 10
list_to_reverse = list(range(number_of_items))
if number_of_items < 15:
print("a: {}".format(list_to_reverse))
print('Loops: {:,}'.format(loops_to_test))
# List of the functions we want to test with the timer, in print order
fcns = [rev_in_place, reversed_iterator, rev_slice, rev_copy_reverse,
reversed_with_list, rev_manual_pos_gen, rev_manual_neg_gen,
rev_manual_index_loop, rev_manual_loop]
max_name_string = max([ len(fcn.__name__) for fcn in fcns ])
for fcn in fcns:
a = copy(list_to_reverse) # copy to start fresh each loop
out_str = ' | out = {}'.format(fcn(a)) if number_of_items < 15 else ''
# Time in ms for the given # of loops on this fcn
time_str = time_str_ms(timeit(lambda: fcn(a), number=loops_to_test))
# Get the output string for this function
fcn_str = '{}(a):'.format(fcn.__name__)
# Add the correct string length to accommodate the maximum fcn name
format_str = '{{fx:{}s}} {{time}}{{rev}}'.format(max_name_string + 4)
print(format_str.format(fx=fcn_str, time=time_str, rev=out_str))
Die Ergebnisse zeigen, dass die Skalierung am besten mit den eingebauten Methoden funktioniert, die für eine bestimmte Art der Umkehrung am besten geeignet sind. Mit anderen Worten, wenn die Anzahl der Objektelemente zunimmt, sind die eingebauten Methoden den anderen Methoden sogar überlegen.
Die eingebaute Methode, die direkt das erreicht, was Sie brauchen, ist besser als die Aneinanderreihung von Dingen. D.h. Slicing ist am besten, wenn Sie eine Kopie der umgekehrten Liste benötigen - es ist schneller als die Erstellung einer doppelten Liste aus list(reversed(obj))
Funktion und schneller als eine Kopie der Liste zu erstellen und dann eine In-Place obj.reverse()
aber nie um mehr als die doppelte Geschwindigkeit. Inzwischen können benutzerdefinierte Methoden bei großen Listen um Größenordnungen länger dauern.
Für die Skalierung bei einer Liste mit 1000 Einträgen wird die reversed(<list>)
Funktionsaufruf braucht ~30 ms, um den Iterator einzurichten, die Umkehrung an Ort und Stelle braucht nur ~55 ms, die Verwendung der Slice-Methode braucht ~210 ms, um eine Kopie der vollständigen umgekehrten Liste zu erstellen, aber die schnellste manuelle Methode, die ich gemacht habe, brauchte ~8400 ms .
Mit 2 Einträgen in der Liste:
a: [0, 1]
Loops: 100,000
rev_in_place(a): 24.70 ms | out = [1, 0]
reversed_iterator(a): 30.48 ms | out = <list_reverseiterator object at 0x0000020242580408>
rev_slice(a): 31.65 ms | out = [1, 0]
rev_copy_reverse(a): 63.42 ms | out = [1, 0]
reversed_with_list(a): 48.65 ms | out = [1, 0]
rev_manual_pos_gen(a): 98.94 ms | out = [1, 0]
rev_manual_neg_gen(a): 88.11 ms | out = [1, 0]
rev_manual_index_loop(a): 87.23 ms | out = [1, 0]
rev_manual_loop(a): 79.24 ms | out = [1, 0]
Die Liste enthält 10 Einträge:
rev_in_place(a): 23.39 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
reversed_iterator(a): 30.23 ms | out = <list_reverseiterator object at 0x00000290A3CB0388>
rev_slice(a): 36.01 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rev_copy_reverse(a): 64.67 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
reversed_with_list(a): 50.77 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rev_manual_pos_gen(a): 162.83 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rev_manual_neg_gen(a): 167.43 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rev_manual_index_loop(a): 152.04 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rev_manual_loop(a): 183.01 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Und mit 1000 Einträgen auf der Liste:
rev_in_place(a): 56.37 ms
reversed_iterator(a): 30.47 ms
rev_slice(a): 211.42 ms
rev_copy_reverse(a): 295.74 ms
reversed_with_list(a): 418.45 ms
rev_manual_pos_gen(a): 8410.01 ms
rev_manual_neg_gen(a): 11054.84 ms
rev_manual_index_loop(a): 10543.11 ms
rev_manual_loop(a): 15472.66 ms
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.