Aus einer Liste Endelemente 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.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Am besten schreibt man solche Funktionen so, dass man jedes iterierbare Objekt übergeben kann.

Code: Alles auswählen

def strip_trailing(sequenze, value):
    result = []
    saved = []
    for element in sequenze:
        saved.append(element)
        if element != value:
            result.extend(saved)
            saved = []
    return result
    
def istrip_trailing(sequenze, value):
    saved = []
    for element in sequenze:
        saved.append(element)
        if element != value:
            for el in saved:
                yield el
            saved = []
So fumktioniert das ganze auch, wenn man Leerzeilen am Ende einer Datei ignorieren will:

Code: Alles auswählen

with open("some_file.txt") as lines:
    for line in istrip_trailing(lines, "\n"):
        print line
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ohne explizite Schleife ist die Aufgabe mit dem Mitteln von Python wohl nicht sinnvoll zu lösen.

Daher hier als Schleife mit reversed(), die zumindest das unpythonische Holen einzelner Elemente über den Index vermeidet:

Code: Alles auswählen

def strip_end(sequence, value):
    for i, item in enumerate(reversed(sequence)):
        if item != value:
            # `i` might be 0, so don't use negative index
            stop = len(sequence) - i
            return sequence[:stop]
    return sequence
 
def main():
    my_list = [
        (1,2,3),
        (4,5,6),
        (0,0,0),
        (7,8,9),
        (0,0,0),
        (0,0,0),
        (0,0,0)
    ]
    stripped = strip_end(my_list, (0, 0, 0))
    print(stripped)
 
if __name__ == '__main__':
    main()
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Hier pillmunchers stabilisierte Variante, ich im Sinne der originalen Frage als die pythonischste sehe (und die zudem ziemlich schnell ist):

Code: Alles auswählen

def strip_end(sequence, value):
    try:
        while sequence[-1] != value:
            sequence.pop()
    except IndexError:
        pass
    return sequence
Alternativ ist 'del sequence[-1]' anstelle von .pop() noch marginal flotter.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@kbr:
Das löst aber leider das Problem nicht. Schau dir mal genauer an, was in Zeile 3 bei dir passiert.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ganze noch etwas schöner, mit groupby

Code: Alles auswählen

from itertools import groupby, chain

def istrip_trailing(sequenze, value):
    saved = []
    for is_value, elements in groupby(sequenze, value.__eq__):
        if is_value:
            saved = list(elements)
        else:
            for element in chain(saved, elements):
                yield element
@kbr: Funktionen, die Listen verändern, sollten diese nicht auch noch als Rückgabewert haben (siehe list.sort vs. sorted)
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

snafu hat geschrieben:@kbr:
Das löst aber leider das Problem nicht. Schau dir mal genauer an, was in Zeile 3 bei dir passiert.
Das Problem löst es schon nur muß es == und nicht != heißen in Zeile 3

Die andere Variante ohne try und except wäre:

Code: Alles auswählen

def remove_trailing(sequence, value):
    for item in reversed(sequence):
        if item != value:
            break
        sequence.pop()
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: das enumerate ist doch völlig überflüssig, weil i nicht verwendet wird. Das Verhalten von reversed ist undefiniert, wenn sich die Liste über die Iteriert wird, sich ändert.

Also korrekt:

Code: Alles auswählen

def remove_trailing(sequence, value):
    while sequence and sequence[-1] == value:
        sequence.pop()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sirius3: Danke, das ist genau die richtige Lösung
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

snafu hat geschrieben:@kbr:
Das löst aber leider das Problem nicht. Schau dir mal genauer an, was in Zeile 3 bei dir passiert.
Oops, typischer copy & paste Typo. Sirius3s Variante ist dann durch Umgehung des try/except noch eleganter. Wobei ich sequence als Ergebnis zusätzlich noch zurückgeben würde.
Antworten