Ich habe eine Liste bestehend aus etwa 20000 Listen. Ich benutze das 3. Element jeder Liste als Flag. Ich möchte einige Operationen an dieser Liste ausführen, solange mindestens ein Element-Flag 0 ist. Es ist wie folgt:
my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....]
Am Anfang sind alle Flags 0. Ich benutze eine while-Schleife, um zu überprüfen, ob das Flag eines Elements 0 ist:
def check(list_):
for item in list_:
if item[2] == 0:
return True
return False
Wenn check(my_list)
zurückkommt True
, arbeite ich weiter an meiner Liste:
while check(my_list):
for item in my_list:
if condition:
item[2] = 1
else:
do_sth()
Eigentlich wollte ich ein Element in my_list entfernen, während ich darüber iterierte, aber ich darf keine Elemente entfernen, während ich darüber iteriere.
Die ursprüngliche my_list hatte keine Flags:
my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....]
Da ich beim Durchlaufen keine Elemente entfernen konnte, habe ich diese Flags erfunden. Aber das my_list
enthält viele Elemente, und die while
Schleife liest alle in jeder for
Schleife und es kostet viel Zeit! Hast du irgendwelche Vorschläge?
quelle
None
oder[]
beim Durchlaufen der Liste ersetzen, anstatt sie zu entfernen. Das Überprüfen der gesamten Liste mit 'check ()', das alle Elemente vor jedem Durchlauf der inneren Schleife durchläuft, ist ein sehr langsamer Ansatz.Antworten:
Die beste Antwort hier ist die Verwendung
all()
, die für diese Situation eingebaut ist. Wir kombinieren dies mit einem Generatorausdruck , um das gewünschte Ergebnis sauber und effizient zu erzielen. Beispielsweise:Beachten Sie, dass dies
all(flag == 0 for (_, _, flag) in items)
direkt gleichbedeutendall(item[2] == 0 for item in items)
ist. In diesem Fall ist es nur ein wenig schöner zu lesen.Und für das Filterbeispiel ein Listenverständnis (natürlich können Sie gegebenenfalls einen Generatorausdruck verwenden):
Wenn Sie überprüfen möchten, ob mindestens ein Element 0 ist, ist es besser, das besser
any()
lesbare zu verwenden:quelle
all()
undany()
Kurzschluss, wenn zum Beispiel auf Mine der erste Wert ausgewertet wirdFalse
,all()
wird fehlschlagen und keine weiteren Werte überprüfen, RückkehrFalse
. Ihr Beispiel wird dasselbe tun, außer dass es zuerst die gesamte Liste der Vergleiche generiert, was viel Verarbeitung für nichts bedeutet.Wenn Sie überprüfen möchten, ob ein Element in der Liste eine Bedingung verletzt, verwenden Sie
all
:Verwenden Sie, um alle nicht übereinstimmenden Elemente zu entfernen
filter
quelle
[...]
inall(...)
da er dann einen Generator statt einer Liste erstellen, die spart Ihnen nicht nur zwei Zeichen , sondern auch Speicher und spart Zeit. Bei Verwendung von Generatoren wird jeweils nur ein Element berechnet (frühere Ergebnisse werden gelöscht, da sie nicht mehr verwendet werden). Wenn sich herausstelltFalse
, dass eines davon nicht mehr berechnet wird , beendet der Generator die Berechnung des Restelements.Sie könnten itertools so lange verwenden, es wird gestoppt, sobald eine Bedingung erfüllt ist, die Ihre Aussage nicht erfüllt. Die entgegengesetzte Methode wäre in der Zwischenzeit
quelle
Eine andere Art zu verwenden
itertools.ifilter
. Dies überprüft die Wahrhaftigkeit und den Prozess (mitlambda
)Stichprobe-
quelle
Dieser Weg ist etwas flexibler als die Verwendung von
all()
:oder prägnanter:
quelle
all_zeros = False in [x[2] == 0 for x in my_list]
oder sogar0 in [x[2] for x in my_list]
und entsprechend dafür sagenany_zeros
? Ich sehe keine bemerkenswerte Verbesserung gegenüberall()
.all_zeros = False in [x[2] == 0 for x in my_list]
ausgewertetFalse
, während meine ausgewertet wirdTrue
. Wenn Sie es ändern,all_zeros = not (False in [x[2] == 0 for x in my_list])
entspricht es meinem. Und0 in [x[2] for x in my_list]
wird offensichtlich nur für arbeitenany_zeros
. Aber ich mag die Prägnanz Ihrer Idee, deshalb werde ich meine Antwort aktualisieren