Der Iterator, den ich zuvor geschrieben habe und der von der Mitte der Sequenz aus vorwärts scannen kann
sslice.py
def sslice(sequence, *slice_args):
return (sequence[index]
for index in range(*slice(*slice_args).indices(len(sequence))))
Es ist sehr praktisch und nützlich für seine kurze Länge.
Wenn du immer bist
Ich möchte einen Iterator, der wie "itertools.islice ()" für Sequenzen verwendet werden kann, schnell ist, auch wenn er von der Mitte aus scannt, und auch vorwärts scannen kann! !! !!
Wenn Sie Angst haben, können Sie jetzt den obigen Code verwenden.
Ich habe keine Ahnung, warum eine solche Funktion vorbereitet ist ...
Wenn Sie denken, lesen Sie bitte die Fortsetzung.
sslice ()
benutztZunächst als konkrete Situation
Ich möchte aus der Liste "L" eine Liste extrahieren, die das "n" -te Element und die maximalen "m" -Elemente davor und danach enthält.
Nehmen wir die Situation an.
Wenn Sie beispielsweise eine Liste mit Ranglisten haben, beträgt Ihre Rangliste 12.345, und Sie möchten jeweils bis zu 5 darüber und darunter anzeigen.
Ich wollte es etwas häufiger machen, aber es tut mir leid, dass ich kein gutes finden konnte.
Beachten Sie, dass wir den Beispielcode einfach halten möchten. Nehmen wir also an, dass das erste Element in der Liste L
das 0. Element anstelle des 1. Elements ist.
In diesem Fall ist der 12.345. Platz das 12.344ste Element.
Darüber hinaus sollte es einfach sein, mit Rängen unter Ihnen umzugehen, sodass wir hier nur die Verarbeitung von Rängen über Ihnen in Betracht ziehen.
Daher ist dieser Prozess
Rufen Sie aus der Liste "L" die Liste mit dem größten "m" -Element vor dem "n" -ten Element ab
Es wurde eine Anforderung. Die Methode, an die ich zu diesem Zeitpunkt dachte, war das Schneiden.
>>> L = list(range(1, 50000+1))
>>> n = 12345 - 1
>>> m = 5
>>> L[max(0, n - m): n]
[12340, 12341, 12342, 12343, 12344]
Es war eine Möglichkeit, einen Teil der Liste mit Code wie zu erhalten.
Natürlich gibt es bei dieser Methode kein besonderes Problem.
Was aber, wenn die Anforderung für diesen Prozess nicht das "maximale" m "-Element voraus ist, sondern das" maximale "m" -Element voraus ", das bestimmte Kriterien erfüllt?
Die Urteilsbedingung ist diesmal einfach
>>> def is_odd(number):
... return (number % 2 == 1)
...
>>> is_odd(1)
True
>>> is_odd(2)
False
Ich werde sagen. Kurz gesagt, es ist eine ungerade Zahl.
In diesem Fall muss bestimmt werden, ob jedes Element die Bedingung erfüllt, so dass zumindest das Schneiden allein das Problem nicht lösen kann, und ein Vorwärtsscan vom "n" -ten Element der Liste ist erforderlich.
Nur für den Fall, wenn ich die Geschichte bisher zusammengefasst habe,
>>> L = list(range(1, 50000+1))
>>> n = 12345 - 1
>>> m = 5
>>> L[max(0, n - m): n]
>>> def is_odd(number):
... return (number % 2 == 1)
...
>>>
Unter der Bedingung
[12343, 12341, 12339, 12337, 12335]
Der Zweck besteht darin, den Prozess zu schreiben, um das Ergebnis zu erhalten.
Am Ende müssen Sie die Ergebnisliste auf "[12335, 12337, 12339, 12341, 12343]" drehen, um sie in der Rangfolge anzuzeigen, aber diesen Vorgang überspringen.
Das erste, was ich überlegte, war, wie man Slices und Listeneinschlussnotation kombiniert.
>>> [rank for rank in L[n - 1::-1] if is_odd(rank)][:m]
[12343, 12341, 12339, 12337, 12335]
Das richtige Ergebnis wurde angezeigt.
Diese Methode macht jedoch den Speicherverbrauch der vorübergehend erzeugten Liste nicht zum Narren, wenn die Anzahl der Elemente in der Liste "L" groß ist.
Daher werde ich diese Methode ablehnen.
islice ()
kann nicht vorwärts scannenDas nächste, was ich überlegte, war, wie man mit einem Iterator unter Verwendung der "islice ()" des "itertools" -Moduls umgeht, das jeder liebt.
>>> from itertools import islice
>>> islice(L, n - 1, None, -1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Step for islice() must be a positive integer or None.
>>>
Aus irgendeinem Grund habe ich einen Fehler erhalten.
Ich habe mich ein wenig gefragt, warum dies ein Fehler sein würde, aber ich habe schließlich herausgefunden, warum, indem ich die Hilfe für "islice ()" gelesen habe.
>>> help(itertools.islice)
Help on class islice in module itertools:
class islice(builtins.object)
| islice(iterable, stop) --> islice object
| islice(iterable, start, stop[, step]) --> islice object
|
| Return an iterator whose next() method returns selected values from an
| iterable. If start is specified, will skip all preceding elements;
| otherwise, start defaults to zero. Step defaults to one. If
| specified as another value, step determines how many values are
| skipped between successive calls. Works like a slice() on a list
| but returns an iterator.
...
Kurz gesagt, "islice ()" sollte eine iterable oder "iter" -Methode oder ein Sequenzobjekt als erstes Argument haben.
Pythons "Listen" -Objekte sind Sequenzen, aber iterierbare Objekte sind nicht immer Sequenzen, sondern oft keine Sequenzen. Sie können also nicht erwarten, dass Sie von der Mitte aus in die entgegengesetzte Richtung scannen können.
Der "Schritt" von "islice ()" wurde so entworfen, dass es keine negative Zahl sein kann.
Ich gebe also nicht auf
Sollte es nicht möglich sein, eine negative Zahl für "step" nur anzugeben, wenn das erste Argument von "islice ()" eine Sequenz ist?
Es ist nicht überraschend, aber anscheinend habe ich keine solche Spezifikation gemacht, weil es in Python nicht schön ist, das Verhalten abhängig von der Art des Arguments zu ändern.
Ich überlasse es den Pythonisten, mir mehr Gedanken darüber zu machen, warum unser Python so korrekt und schön ist. Und ich werde auf die Geschichte des Erreichens dieses Ziels zurückkommen.
Ich habe viel darüber nachgedacht, aber am Ende habe ich "islice ()" und "sslice ()" für die Sequenz geschrieben.
def sslice(sequence, *slice_args):
return (sequence[index]
for index in range(*slice(*slice_args).indices(len(sequence))))
Der folgende Code wurde mit der Sorgfalt geschrieben, Slices nicht mit sslice ()
zu erweitern.
>>> list(islice((rank for rank in sslice(L, n - 1, None, -1) if is_odd(rank)), 0, m))
[12343, 12341, 12339, 12337, 12335]
Damit habe ich dieses Ziel endlich erreicht.
Übrigens scheint "islice ()" den Iterator ("i") des Slice des iterierbaren Objekts ("Slice") zu bedeuten. Wenn Sie also den Iterator des Slice der Sequenz "sslice ()" nennen, handelt es sich um einen frommen Pythonista. Es scheint von Leuten beschimpft zu werden, aber bitte haben Sie Verständnis dafür, dass es sehr einfach ist, sich an "islice ()" zu erinnern, wenn Sie Iterator-Slices möchten, und an "sslice ()", wenn Sie Sequenz-Slices möchten.
sslice ()
schneller ist alsislice ()
sslice ()
greift über Indizes auf die Sequenz zu, daher ist es normalerweise schneller, die verschiedenen optimiertenislice ()
zu verwenden, wenn Sie mit
islice () `das gleiche Ergebnis erzielen können. Es kann jedoch schneller sein, "sslice ()" zu verwenden, wenn das Argument "start" einen großen Wert hat.
Der Grund ist, dass "islice ()" von Anfang an sequentiell verarbeitet werden muss, während auf "sslice ()" per Index zugegriffen werden kann.
Früher habe ich geschrieben, dass "es einfach sein sollte, mit den Rängen unter Ihnen umzugehen", aber es ist besser, auch dafür "sslice ()" zu verwenden.
Es scheint, dass es mehrere Verbesserungswünsche bezüglich dieser Einschränkung oder Spezifikation von "islice ()" gegeben hat, die aber anscheinend oben erwähnt wurden.
In Python ist es nicht schön, das Verhalten je nach Art des Arguments zu ändern
Es scheint, dass es aus diesem Grund abgelehnt wurde.
Wenn Sie ein gut ausgebildeter Python-Benutzer sind, werden Sie weinen und weinen, sobald Sie die Erklärung hören.
Wie erwartet Pythonista! Es ist einfach, Dinge loszuwerden, bei denen Korrektheit Vorrang vor Benutzerfreundlichkeit hat. Ich sehne mich danach!
Ich muss mich vielleicht ausziehen und das Eiswasser im Eimer von meinem Kopf abdecken, aber ich bin ein bisschen schwach und ich bin nicht gut darin, aber bitte lass mich passieren.
Ich habe einen Iterator geschrieben, der von der Mitte der Sequenz aus vorwärts scannen kann.
sslice.py
def sslice(sequence, *slice_args):
return (sequence[index]
for index in range(*slice(*slice_args).indices(len(sequence))))
Obwohl es kurz ist, ist es sehr praktisch und nützlich. Wenn Sie also einen Iterator möchten, der wie "itertools.islice ()" für Sequenzen verwendet werden kann, schnell ist, auch wenn Sie von der Mitte aus scannen und vorwärts scannen können, verwenden Sie ihn bitte. Bitte gib mir.
Es ist so kurz, dass ich dachte, vielleicht hätte jemand in der Vergangenheit eine ähnliche Funktion geschrieben, aber ich habe nur den gleichen Code gefunden, mit Ausnahme des Variablennamens, sodass ich die Lizenz nicht beanspruchen kann.
Bitte zögern Sie nicht, es zu benutzen.
Übrigens verwendet sslice () slice.indices (), weil
>>> sslice(range(20), None, None, -1)
Dies soll Argumenten wie entsprechen.
Es gibt viele Teile der Python-Hilfedokumentation, die so verwirrend sind, dass Sie sich fragen könnten: "Ist das absichtlich geschrieben?", Und die Hilfe für "Slice.indices ()" ist eine davon. Überlegen.
>>> help(slice.indices)
Help on method_descriptor:
indices(...)
S.indices(len) -> (start, stop, stride)
Assuming a sequence of length len, calculate the start and stop
indices, and the stride length of the extended slice described by
S. Out of bounds indices are clipped in a manner consistent with the
handling of normal slices.
(END)
Ich bin nicht der einzige, der auf den ersten Blick nicht verstanden hat, was der Zweck dieser Methode war, nachdem er die obige Hilfe gelesen hat, oder? (Schweiß
Ein solches "Slice.indices ()" wird empfohlen, da es auf einmal entschieden wird, ob Sie es verwenden, wenn Sie ein Argument von "range ()" aus einem "Slice" -Objekt generieren möchten.
Vielleicht gibt es keine anderen Situationen, in denen diese Methode nützlich ist. (Lol)
Recommended Posts