Seite 1 von 2
					
				Aus einer Liste Endelemente entfernen
				Verfasst: Samstag 20. Mai 2017, 21:01
				von Alfons Mittelmeyer
				Ich wollte einmal fragen, ob es einen Python Befehl für so etwas gibt.
Ich habe eine Liste:
Code: Alles auswählen
my_list = [ (1,2,3),
            (4,5,6),
            (7,8,9),
            (0,0,0),
            (0,0,0),
            (0,0,0) ]
Und daraus möchte ich die (0,0,0) Elemente am Ende entfernen.
Gibt es für so etwas eine Python Funktion oder macht man das auf herkömmliche Art mit einer Schleife?
Meine Lösung sähe so aus:
Code: Alles auswählen
def remove_trailing_elements(some_list,trailing_value):
    for index in range(len(some_list)-1,-1,-1):
        if some_list[index] == trailing_value:
            some_list.pop(index)
Aber entspricht die der Python Philosophie, dass es nur genau eine richtige Lösung geben soll?
Aber welche ist da dann die Richtige?
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Samstag 20. Mai 2017, 21:42
				von karolus
				Code: Alles auswählen
from itertools import takewhile, filterfalse
list(takewhile(lambda x: x!=(0,0,0), my_list))
#oder
list(filterfalse(lambda x: x==(0,0,0), my_list))
takewhile nur falls die nicht gewünschten Elemente zusammen am Ende stehen.
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Samstag 20. Mai 2017, 22:00
				von pillmuncher
				Code: Alles auswählen
>>> my_list = [
...     (1, 2, 3),
...     (4, 5, 6),
...     (7, 8, 9),
...     (0, 0, 0),
...     (0, 0, 0),
...     (0, 0, 0)
... ]
>>> my_list
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (0, 0, 0), (0, 0, 0), (0, 0, 0)]
>>> while my_list[-1] == (0, 0, 0):
...     my_list.pop()                                                           
... 
(0, 0, 0)
(0, 0, 0)
(0, 0, 0)
>>> my_list
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Samstag 20. Mai 2017, 22:33
				von Alfons Mittelmeyer
				@pillmuncher: ja das ist kurz und prägnant. Bei der for Schleife habe ich glatt noch etwas vergessen, nämlich else: break
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Samstag 20. Mai 2017, 23:35
				von kbr
				@pillmuncher: die Lösung ist geradlinig. Als Edgecase müsste noch ein IndexError abgefangen werden.
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 07:07
				von snafu
				Code: Alles auswählen
def strip_end(sequence, value):
    try:
        stop = sequence.index(value)
    except ValueError:
        stop = None
    return sequence[:stop]
def main():
    my_list = [
        (1,2,3),
        (4,5,6),
        (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()
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 08:44
				von Alfons Mittelmeyer
				@snafu: Deine Lösung funktioniert aber hier nicht:
Code: Alles auswählen
def strip_end(sequence, value):
    try:
        stop = sequence.index(value)
    except ValueError:
        stop = None
    return sequence[:stop]
 
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()
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 09:09
				von snafu
				Richtig. Für den Fall, den du in Zeile 12 zeigst, funktioniert es nicht. Bisher war ja von Endelementen die Rede. Aber scheinbar ist die tatsächliche Anforderung anders als die zuvor beschriebene Anforderung. Du willst also nicht nur Elemente vom Ende der Liste entfernen, sondern alle Elemente, die dem angegebenen Objekt entsprechen...?
EDIT:
Im Übrigen funktionieren die anderen gezeigten Lösungen für diese neue Anforderung genau so wenig.
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 09:14
				von snafu
				Eine Möglichkeit, alle Tuple mit Nullen loszuwerden:
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 09:24
				von snafu
				Am schnellsten ist übrigens eine LC ohne Funktionsaufrufe:
Code: Alles auswählen
zero_tuple = (0, 0, 0)
[tup for tup in my_list if tup != zero_tuple]
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 09:28
				von Alfons Mittelmeyer
				snafu hat geschrieben:Richtig. Für den Fall, den du in Zeile 12 zeigst, funktioniert es nicht. Bisher war ja von Endelementen die Rede. Aber scheinbar ist die tatsächliche Anforderung anders als die zuvor beschriebene Anforderung. Du willst also nicht nur Elemente vom Ende der Liste entfernen, sondern alle Elemente, die dem angegebenen Objekt entsprechen...?
Nein es ist keine neue Anforderung aber deine Lösung funktioniert nicht. Die Lösung soll trailing Elemente am Ende entfernen, vergleichber mit Leerzeichen am Stringende. Deine Lösung kappt aber alles ab dem ersten 'Leerzeichen', das soll sie natürlich nicht.
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 09:33
				von Alfons Mittelmeyer
				@pillmuncher: ich lande bei Berücksichtigung von Randbedingungen und unter Berücksichtigung dass man auch pop nicht braucht, doch bei der for Schleife:
Code: Alles auswählen
def strip_end(sequence, value):
    for index in range(len(sequence)-1,-1,-1):
        if sequence[index] != value:
            return sequence[0:index+1]
    return []
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)
    stripped = strip_end([(0,0,0)],(0,0,0))
    print(stripped)
    stripped = strip_end([],(0,0,0))
    print(stripped)
if __name__ == '__main__':
    main()
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 09:33
				von snafu
				@Alfons:
Sorry, hab meinen Fehler jetzt erkannt. 

 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 09:40
				von Alfons Mittelmeyer
				@snafu: und nach was suchst Du mit: stop = sequence.index(value)
Nach dem ersten Vorkommen des Elementes das aber hinten als trailing zu entfernen ist. Deine Lösung funktioniert nicht.
Python wird es ja wohl wissen und zeigt: [(1, 2, 3), (4, 5, 6)]
Das war eine Überschneidung mit Deinem letzten Post. Meiner war vor deinem letzten Post gedacht.
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 09:56
				von Alfons Mittelmeyer
				Unter Berücksichtigung, dass die ursprüngliche Liste abzuschneiden ist und dass man nur in einem Spezialfall solche trailing Elemente hat, ist wohl doch am Besten:
Code: Alles auswählen
def remove_trailing(sequence, value):
    for index in range(len(sequence)-1,-1,-1):
        if sequence[index] != value:
            break
        else:
            sequence.pop()
 
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)    ]
    remove_trailing(my_list,(0,0,0))
    print(my_list)
 
if __name__ == '__main__':
    main()
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 10:00
				von Sirius3
				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
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 10:05
				von snafu
				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()
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 10:15
				von kbr
				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.
 
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 10:27
				von snafu
				@kbr:
Das löst aber leider das Problem nicht. Schau dir mal genauer an, was in Zeile 3 bei dir passiert.
			 
			
					
				Re: Aus einer Liste Endelemente entfernen
				Verfasst: Sonntag 21. Mai 2017, 10:29
				von Sirius3
				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)