Seite 1 von 1
Flatten a sequence
Verfasst: Donnerstag 24. Juli 2014, 14:08
von bwbg
Zur Problemstellung
flatten a sequence zu Hauf Lösungen mit Hilfsliste finden kann, hier eine Generator-Lösung:
Code: Alles auswählen
def flatten(xs):
"""
>>> list(flatten([1, 2, [3, 4], [5, [6, 7]], 8]))
[1, 2, 3, 4, 5, 6, 7, 8]
"""
for x in xs:
try:
for e in flatten(iter(x)):
yield e
except TypeError: # x is not iterable
yield x
Grüße ... bwbg
Re: Flatten a sequence
Verfasst: Donnerstag 24. Juli 2014, 14:12
von BlackJack
@bwbg: Probier das mal mit einer Zeichenkette irgendwo als Datum aus.

Re: Flatten a sequence
Verfasst: Donnerstag 24. Juli 2014, 20:23
von bwbg
Ja, die Endlosrekursion

verrate es nur keinem.
Re: Flatten a sequence
Verfasst: Freitag 25. Juli 2014, 08:33
von bwbg
Das Problem bei Zeichenketten ist, das deren Elemente wiederum Zeichenketten sind (welche nur ein Zeichen enthalten) und damit iterierbar sind. Um das Problem mit der Endlosrekursion zu beseitigen, habe ich eine Weiche vorgeschaltet, welche die Länge der Sequenz prüft. Praktisch ist, dass `len` einen auch TypeError wirft, wenn es keine Länge zu ermitteln gibt.
Minimal geänderte Funktion mit neuem test-case:
Code: Alles auswählen
def flatten(xs):
"""
>>> list(flatten([1, 2, [3, 4], [5, [6, 7]], 8]))
[1, 2, 3, 4, 5, 6, 7, 8]
>>> list(flatten([[1, 2], "FooBar", 3, 4]))
[1, 2, 'F', 'o', 'o', 'B', 'a', 'r', 3, 4]
"""
for x in xs:
try:
if len(x) > 1:
for e in flatten(iter(x)):
yield e
else:
yield x[0]
except TypeError: # x is not iterable OR has no len()
yield x
Hier stellt sich allerdings die Frage, wie man Zeichenketten behandeln möchte. Derzeit werden diese als Sequenz (von Zeichen) betrachtet. Möglich wäre auch eine Betrachung als "Einheit", jedoch müsste man hier auf den speziellen Typ prüfen, was ich gerne vermeiden möchte.
Grüße ... bwbg
Re: Flatten a sequence
Verfasst: Freitag 25. Juli 2014, 10:46
von Sirius3
Und was passiert mit Listen mit 0 Elementen? Ein IndexError.
Re: Flatten a sequence
Verfasst: Freitag 25. Juli 2014, 13:08
von snafu
Code: Alles auswählen
from collections import Iterable
try:
STRING_TYPES = (str, unicode)
except NameError:
# Assume Python 3.x
STRING_TYPES = (str, bytes)
def flatten(obj):
for item in obj:
if isinstance(item, Iterable) and not isinstance(item, STRING_TYPES):
for subitem in flatten(item):
yield subitem
else:
yield item
Re: Flatten a sequence
Verfasst: Freitag 25. Juli 2014, 13:13
von BlackJack
@snafu: Damit würde man jetzt aber Objekte die zwar iterierbar sind, aber nicht `Iterable`, nicht flachklopfen. Ob ein Objekt tatsächlich (nicht) iterierbar ist, kann man letztendlich nur durch ausprobieren heraus finden. Da gibt es keinen Test den man vorher machen könnte.
Re: Flatten a sequence
Verfasst: Freitag 25. Juli 2014, 13:21
von snafu
@BlackJack: Hast du ein konkretes Beispiel, wo mein Vorab-Test nicht greifen würde?
Re: Flatten a sequence
Verfasst: Freitag 25. Juli 2014, 13:32
von EyDu
Bei dem hier zum Beispiel:
Code: Alles auswählen
from collections import Iterable
class It(object):
def __getitem__(self, index):
if index < 5:
return 2*index
else:
raise IndexError
if __name__ == "__main__":
it = It()
print isinstance(it, Iterable)
for elem in it:
print elem
Re: Flatten a sequence
Verfasst: Freitag 25. Juli 2014, 13:59
von snafu
Gut zu wissen...