Elemente aus einer Liste entfernen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
th.wieland
User
Beiträge: 3
Registriert: Dienstag 29. September 2020, 15:29
Wohnort: Krummhörn

Hallo zusammen,

ich habe eine Liste, aus welcher ich bestimmte Elemente entfernen will.
Dazu hab ich einiges probiert, was nicht funktioniert.
Das hier funktioniert:

Code: Alles auswählen

liste0 = ['3ac','dfg','hjk','5tg','8qs','cv','cvb','2cv','r4','4wd','df','lfx']
liste1 = []
for i in liste0:
    if re.match('^\d',i):
        liste1.append(i)
liste1
['3ac', '5tg', '8qs', '2cv', '4wd']
Gibt es dafür einen eleganteren, pythonischeren Weg ?
Was mich an der Lösung stört ist, dass ich eine weitere Liste erzeugen muss.
Ich würde die nicht passenden Elemente gerne aus der Ursprungsliste löschen.
Hab ich mit del und for i in range(len(l)) probiert, aber durch das Löschen wird die Liste kürzer
und irgendwann gibt's n Index Error :roll:

vielen Dank
Tom
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und genau weil durch das loeschen die Liste kuerzer wird, macht man das eben nicht, dass man eine Liste (oder jede Datenstruktur) manipuliert, statt eine neue zu erzeugen. Das ist also schon richtig so. Du kannst das natuerlich kompakter gestalten durch eine list-comprehension, und durch bessere Namen.

Code: Alles auswählen

all_things = ['3ac','dfg','hjk','5tg','8qs','cv','cvb','2cv','r4','4wd','df','lfx']
things_that_start_with_a_number = [item for item in all_things if len(item) and item[0].isdigit()]
print(things_that_start_with_a_number)
Benutzeravatar
__blackjack__
User
Beiträge: 14056
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@th.wieland: Der pythonische Weg *ist* es eine neue Liste zu erstellen. Das kann man mit einer „list comprehension“ etwas kompakter schreiben. Oder mit `re.compile()`, `filter()`, und `list()` arbeiten:

Code: Alles auswählen

In [213]: items                                                                 
Out[213]: 
['3ac',
 'dfg',
 'hjk',
 '5tg',
 '8qs',
 'cv',
 'cvb',
 '2cv',
 'r4',
 '4wd',
 'df',
 'lfx']

In [214]: [item for item in items if re.match("\d", item)]                      
Out[214]: ['3ac', '5tg', '8qs', '2cv', '4wd']

In [215]: list(filter(re.compile("\d").match, items))                           
Out[215]: ['3ac', '5tg', '8qs', '2cv', '4wd']
Den "^" braucht man bei der `match()`-Methode nicht, der ist da implizit schon enthalten.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Nufnus
User
Beiträge: 18
Registriert: Sonntag 29. November 2020, 21:40

Mein Gedanke war jetzt eigentlich, dass er einfach nicht über den index iterieren darf, sondern so (wie in dem nicht auskommentiertem Code):

Code: Alles auswählen

def main():
    names = ["Karla", "Max", "Rudolf", "Lisa"]

    for name in names:
        if name == "Max":
            names.remove(name)
            print(name + " gelöscht")

    print(names)


# def main():
#     names = ["Karla", "Max", "Rudolf", "Lisa"]

#     for i in range(0, len(names)):
#         if names[i] == "Max":
#             names.remove(names[i])
#             print(names[i] + " gelöscht")

#     print(names)
    
if __name__ == "__main__":
    main()

Ist das echt schlechter Stil?
Sicher müsste es doch sein, oder? Funktioniert bei mir recht zuverlässig.
Für jede Änderung an einer Datenstruktur immer gleich eine neue Datenstruktur erstellen zu müssen, stelle ich mir Performancetechnisch auch irgendwie nicht so toll vor?
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

__blackjack__ hat geschrieben: Dienstag 13. Juli 2021, 17:18 @th.wieland: Der pythonische Weg *ist* es eine neue Liste zu erstellen. Das kann man mit einer „list comprehension“ etwas kompakter schreiben. Oder mit `re.compile()`, `filter()`, und `list()` arbeiten:
Naja, Regular Expressions sind zwar sehr bequem und angenehm, aber leider nicht besonders performant, und in diesem Fall auch überflüssig:

Code: Alles auswählen

In [13]: %timeit [item for item in items if re.match('\d', item)]
6.32 µs ± 54.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [14]: %timeit list(filter(re.compile("\d").match, items))
2.39 µs ± 50.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [15]: %timeit list(filter(lambda item: item[0].isdigit(), items))
1.41 µs ± 80.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [16]: %timeit [item for item in items if item[0].isdigit()]
799 ns ± 3.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Klar, bei so Kleckerkram macht das wenig, aber... ;-)
Benutzeravatar
__blackjack__
User
Beiträge: 14056
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@LukeNukem: Bei den `isdigit()`-Varianten fehlt noch der Test ob `item` überhaupt etwas enthält den __deets__ in seinem Beispiel drin hat.

@Nufnus: Das funktioniert halt nicht wirklich *und* ist unperformant, weil bei jedes `remove()` die Liste wieder von vorne durchgeht und das Argument sucht, obwohl man den Index davon ja eigentlich schon kennt, und löschen bedeutet alle Elemente danach eine Position nach vorne zu kopieren. Was das nicht funktionieren angeht: Steck mal zweimal "Max" hintereinander in die Ausgangsliste und schau Dir das Ergebnis an.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
th.wieland
User
Beiträge: 3
Registriert: Dienstag 29. September 2020, 15:29
Wohnort: Krummhörn

Hallo zusammen,
vielen Dank für die Tipps und die interessante Diskussion.
Das hat mich wieder ein gutes Stück weitergebracht.
Die for-Schleife durch List-comprehension zu ersetzen finde ich sehr elegant.
Damit bin ich noch nicht so vertraut. - Werd ich künftig vermehrt einsetzen.
Das Beispiel war etwas abstrahiert - die List-Elemente könnten auch andere Inhalte haben,
deshalb hab ich die Regex gewählt.
War mir auch nicht klar, dass die so auf die Performance gehen.
cu Tom
Nufnus
User
Beiträge: 18
Registriert: Sonntag 29. November 2020, 21:40

__blackjack__ hat geschrieben: Mittwoch 14. Juli 2021, 00:17 @Nufnus: Was das nicht funktionieren angeht: Steck mal zweimal "Max" hintereinander in die Ausgangsliste und schau Dir das Ergebnis an.
Wow, das hätte ich jetzt nicht erwartet.
Vielen Dank auch von mir :o
Antworten