Effiziente iteration über slice in Python
Wie effizient sind die Iterationen über slice-Operationen in Python? Und wenn eine Kopie ist unvermeidlich mit Scheiben, gibt es eine alternative?
Ich weiß, dass eine slice-operation über eine Liste ist O(k), wobei k die Größe der Scheibe.
x[5 : 5+k] # O(k) copy operation
Jedoch bei der Iteration über einen Teil einer Liste ist, finde ich, dass die sauberste (und die meisten Pythonic?) Weg, dies zu tun (die zimmerreserviereung, ohne das resort zu den Indizes) ist zu tun:
for elem in x[5 : 5+k]:
print elem
Aber meine intuition ist, dass diese Ergebnisse noch in eine teure Kopie der Teilliste, anstatt einfach nur die Iteration über die vorhandene Liste.
- Wenn Sie besorgt sind, zum kopieren der Scheibe, ich denke, die alternative ist, Durchlaufen die Indizes mit
range(5, 5 + k)
. - Gefahr! Sie habe schlechte Beratung früher;
itertools.islice
nicht so funktionieren, wie wir es uns gedacht haben. Wenn Sie eineislice
ab 1000000, Python wird die Schleife durch die erste 1000000 Elemente Ihrer Liste, bevor Sie nachgeben nichts. Dies könnte wiederum eine linear-Zeit-Algorithmus quadratische oder schlechter.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie
itertools.islice
um eine geschnittene iterator aus der Liste:Beispiel:
Update:
Wie bereits von @user2357112 die Leistung
islice
hängt von dem start Punkt der Scheibe und der Größe der iterierbar normale Scheibe wird blitzschnell in fast allen Fällen und sollte bevorzugt werden. Hier sind einige weitere timing-Vergleiche:Für Riesige Listen
islice
ist etwas schneller, oder gleich normale Scheibe, wenn die Scheibe ist Startpunkt ist weniger als die Hälfte der Größe der Liste, für die größeren Indizes normalen Scheibe ist der klare Sieger.Für Kleinen Listen normale Scheibe ist schneller als
islice
für fast alle Fälle.Fazit:
Gehen für den normalen Scheiben.
itertools.islice
funktioniert nicht auf diese Weise! Es ist gebaut für das schneiden von beliebigen iterables, und es wird nicht versuchen, Sie zu verwenden__getitem__
. Wenn Sie versuchen, eineislice
ab1000000
,islice
wird eine Schleife durch die erste1000000
Elemente Ihrer Liste, bevor die nachgeben, nichts, völlig zerstören Ihre Leistung.islice
.lis
, und welche Python-version ist das? Mein timing die Ergebnisse sind das Gegenteil von Euch.range(10**6)
. Dies ist IPython-shell, py2.7.4.islice
gewinnen können, wenn die Scheibe größer ist als der Teil, dass kommt vor, aber wennstart
ist viel größer alsstop - start
-, Leistungs-tanks. Siehe timing-Daten in meine (korrigierte) Antwort.islice
ist die Einnahme von Millisekunden.Verwenden:
Es ist Pythonic! Diese änderung nicht, bevor Sie haben profilierten Sie den code und bestimmt, dass dies ein Engpass -- obwohl ich bezweifle, dass Sie jemals finden, dass dies die wichtigste Quelle von einem Engpass.
In Bezug auf Geschwindigkeit, es wird wahrscheinlich Ihre beste Wahl sein:
In Bezug auf Speicher, es ist nicht so schlimm, könnte man denken.
x[5: 5+k]
ist ein flachen Kopie von Teilx
. Also, auch wenn die Objekte inx
sind groß,x[5: 5+k]
ist eine neue Liste zu erstellen mit k-Elemente verweisen auf die gleichen Objekte wie in derx
. So brauchen Sie nur extra Speicher zum erstellen einer Liste mit k Verweise auf bereits bestehende Objekte. Das ist wahrscheinlich nicht gehen, um die Quelle der Probleme mit dem Speicher.Nur durchqueren die gewünschten Indizes, es gibt keine Notwendigkeit, erstellen Sie eine neue Scheibe für dieses:
Zugegeben: es sieht unpythonic, aber es ist effizienter als das erstellen eines neuen Segments in dem Sinne, dass kein zusätzlicher Speicher ist verschwendet. Eine alternative wäre die Verwendung eines iterator, wie gezeigt, in @AshwiniChaudhary Antwort.
IndexError
.timeit
. Iteratoren und die Scheiben sind nicht besonderes, Sie sind basic, core Python-Funktionen.Bist du schon dabei eine O(n) iteration über die Scheibe. In den meisten Fällen ist dies viel mehr ein Anliegen, als die eigentliche Gestaltung der Scheibe, was passiert, ganz in der optimierten C. Looping über eine Scheibe, sobald Sie gemacht haben, dauert es mehr als doppelt so lang wie die Scheibe, auch wenn man gar nichts mit:
Könnten Sie versuchen, Durchlaufen die Indizes mit
xrange
, aber für die Buchhaltung benötigte Zeit zum abrufen der Liste element, es ist langsamer als schneiden. Auch wenn Sie überspringen Sie diesen Teil, es immer noch nicht, beat-slicing:Nicht verwenden
itertools.islice
dafür!!!! Es wird Schleife durch die Liste von Anfang an und nicht als den Sprung auf die Werte, die Sie möchten mit__getitem__
. Hier einige timing-Daten, die zeigen, wie seine Leistung hängt davon ab, wo die Scheibe beginnt:Hier
islice
verlieren regelmäßige schneiden:Dies ist auf Python 2.7.5, im Falle eines späteren Versionen hinzufügen Liste-spezifische Optimierungen.
Ich denke, ein besserer Weg ist, mit einer c-ähnlichen iteration, wenn der 'k' ist so groß (wie ein großes " k " - wie 10000000000000 - selbst machen könnte, warten Sie etwa 10 Stunden, um die Antwort in einer pythonic for-Schleife)
hier ist, was ich versuche zu sagen Sie tun:
Ich nehme an, dies könnte man Sie nicht einfach in 5 Stunden (ab der pythonic äquivalente for-Schleife tun Sie es für etwa 10 Stunden), dass für große k, dass ich sagte, weil Sie brauchen, um zu gehen von 5 bis 10000000000005 nur einmal!
jede Verwendung von 'range()' von 'xrange()' oder auch das schneiden selbst (als yo oben erwähnt) machen das Programm nur tun 20000000000000 Iterationen, die dazu führen könnten, die eine längere Ausführungszeit, denke ich. (wie Lerne ich mit einem generator-Methode zur Rückgabe eines wiederholenden Objekt, müssen den generator laufen zuerst komplett gemacht werden, und es dauert doppelt Zeit zu tun, job; Eine für den generator selbst und die andere für die 'for' - Schleife)
Herausgegeben:
In python 3 die generator-Methode/Objekt nicht ausführen müssen, um den ersten zu machen, die iterierbar-Objekt für die for-Schleife