Wie überprüfe ich, ob alle Elemente einer Liste einer Bedingung entsprechen?

Lesezeit: 5 Minuten

Benutzer-Avatar
alwbtc

Ich habe eine Liste, die aus etwa 20000 Listen besteht. Ich verwende das dritte Element jeder Liste als Flag. Ich möchte einige Operationen auf dieser Liste ausführen, solange das Flag mindestens eines Elements 0 ist, es ist wie:

my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....]

Am Anfang sind alle Flags 0. Ich verwende eine While-Schleife, um zu prüfen, ob das Flag mindestens eines Elements 0 ist:

def check(list_):
    for item in list_:
        if item[2] == 0:
            return True
    return False

Wenn check(my_list) kehrt zurück Truedann 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 iteriere, aber ich darf keine Elemente entfernen, während ich darüber iteriere.

Ursprüngliche my_list hatte keine Flags:

my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....]

Da ich beim Iterieren keine Elemente entfernen konnte, habe ich diese Flags erfunden. Aber die my_list enthält viele Elemente, und while Schleife liest alle von ihnen bei jedem for Schleife, und es kostet viel Zeit! Haben Sie Vorschläge?

  • Sieht so aus, als wäre Ihre Datenstruktur nicht ideal für Ihr Problem. Wenn Sie den Kontext etwas genauer erklären, könnten wir vielleicht etwas Passenderes vorschlagen.

    – uselpa

    19. Mai 2012 um 14:50 Uhr

  • Vielleicht könntest du die Items durch ersetzen None oder [] wenn Sie die Liste durchlaufen, anstatt sie zu entfernen. Das Überprüfen der gesamten Liste mit ‘check()’, das vor jedem Durchgang durch die innere Schleife über alle Elemente iteriert, ist ein sehr langsamer Ansatz.

    – Martinau

    19. Mai 2012 um 20:08 Uhr

Benutzer-Avatar
Gareth Latty

Die beste Antwort hier ist zu verwenden all(), die für diese Situation integriert ist. Wir kombinieren dies mit a Generatorausdruck um sauber und effizient das gewünschte Ergebnis zu erzielen. Zum Beispiel:

>>> items = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
True
>>> items = [[1, 2, 0], [1, 2, 1], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
False

Beachten Sie, dass all(flag == 0 for (_, _, flag) in items) ist direkt äquivalent zu all(item[2] == 0 for item in items)es ist in diesem Fall nur etwas schöner zu lesen.

Und für das Filterbeispiel ein Listenverständnis (natürlich könnten Sie gegebenenfalls einen Generatorausdruck verwenden):

>>> [x for x in items if x[2] == 0]
[[1, 2, 0], [1, 2, 0]]

Wenn Sie überprüfen möchten, ob mindestens ein Element 0 ist, ist die bessere Option zu verwenden any() was besser lesbar ist:

>>> any(flag == 0 for (_, _, flag) in items)
True

  • Mein Fehler bei der Verwendung von Lambda, Python’s all akzeptiert keine Funktion als erstes Argument wie Haskell et. al., ich habe meine Antwort auch in ein Listenverständnis geändert. 🙂

    – Hampus Nilsson

    19. Mai 2012 um 15:11 Uhr

  • @HampusNilsson Ein Listenverständnis ist nicht dasselbe wie ein Generatorausdruck. Wie all() und any() Kurzschluss, wenn zum Beispiel der erste Wert auf meinen wertet False, all() schlägt fehl und überprüft keine weiteren Werte und kehrt zurück False. Ihr Beispiel wird dasselbe tun, außer dass es zuerst die gesamte Liste der Vergleiche generiert, was viel Verarbeitung für nichts bedeutet.

    – Gareth Latty

    19. Mai 2012 um 15:18 Uhr

  • Es funktioniert auch, wenn Sie dies tun all([ cond(i) for i in range (n) ])

    – Charly Parker

    10. Mai 2021 um 15:59 Uhr

  • @CharlieParker Es zu einem solchen Listenverständnis zu machen, macht die Dinge nur langsamer, wie in meinem vorherigen Kommentar besprochen. Sie möchten einen Generatorausdruck (keine eckigen Klammern) verwenden, da dies zu einem Kurzschluss führen kann.

    – Gareth Latty

    10. Mai 2021 um 16:01 Uhr

  • @GarethLatty ah, interessanter Punkt. Ich bin mir nicht sicher, warum die Optimierung funktioniert, aber das war mir nicht klar all arbeitete für Listen als Eingaben, was der Anwendungsfall war, um den ich mich kümmerte (z. B. Debuggen oder bereits vorhandene Listen). Danke aber für den Tipp!

    – Charly Parker

    10. Mai 2021 um 16:09 Uhr

Benutzer-Avatar
Hampus Nilsson

Wenn Sie überprüfen möchten, ob ein Element in der Liste gegen eine Bedingung verstößt, verwenden Sie all:

if all([x[2] == 0 for x in lista]):
    # Will run if all elements in the list has x[2] = 0 (use not to invert if necessary)

Verwenden Sie zum Entfernen aller nicht übereinstimmenden Elemente filter

# Will remove all elements where x[2] is 0
listb = filter(lambda x: x[2] != 0, listb)

  • Sie können entfernen [...] in all(...) da es dann statt einer Liste einen Generator erstellen kann, was Ihnen nicht nur zwei Zeichen, sondern auch Speicher und Zeit spart. Durch die Verwendung von Generatoren wird jeweils nur ein Element berechnet (frühere Ergebnisse werden gelöscht, da sie nicht mehr verwendet werden) und wenn sich eines davon ergibt Falsebeendet der Generator die Berechnung des Rests.

    – InQβ

    22. Mai 2018 um 12:29 Uhr

  • Hinweis für python3; filter() gibt ein Iterable zurück, keine Liste. So wäre die Leitung listb = list(filter(lamba x: x[2] != 0, listb))

    – Meg Anderson

    10. August 2020 um 18:10 Uhr

Sie könnten das takewhile von itertools so verwenden, dass es aufhört, sobald eine Bedingung erfüllt ist, die Ihre Aussage nicht erfüllt. Die entgegengesetzte Methode wäre dropwhile

for x in itertools.takewhile(lambda x: x[2] == 0, list)
    print x

Benutzer-Avatar
Müllhausen

Dieser Weg ist etwas flexibler als die Verwendung all():

my_list = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
all_zeros = False if False in [x[2] == 0 for x in my_list] else True
any_zeros = True if True in [x[2] == 0 for x in my_list] else False

oder kürzer:

all_zeros = not False in [x[2] == 0 for x in my_list]
any_zeros = 0 in [x[2] for x in my_list]

Eine andere Art der Verwendung itertools.ifilter. Dies überprüft die Richtigkeit und den Prozess (unter Verwendung von lambda)

Probe-

for x in itertools.ifilter(lambda x: x[2] == 0, my_list):
    print x

1073730cookie-checkWie überprüfe ich, ob alle Elemente einer Liste einer Bedingung entsprechen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy