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)