Probleme über List umwandeln

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.
coffeepig
User
Beiträge: 3
Registriert: Donnerstag 13. November 2008, 09:21

Donnerstag 13. November 2008, 09:28

Hallo zusammen,

Ich habe jetzt eine List wie z.B

Code: Alles auswählen

[a,[b,[c]]]
, wie kann ich dies List leicht um Form

Code: Alles auswählen

[a,b,c]
zu wandlen?

was meint ihr?

Grüßen
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Donnerstag 13. November 2008, 10:07

Moin,

wie wäre denn Dein Ansatz?

Gruß,
Manuel
coffeepig
User
Beiträge: 3
Registriert: Donnerstag 13. November 2008, 09:21

Donnerstag 13. November 2008, 11:24

Ich habe so gemacht:

Code: Alles auswählen

def foo(lst):
   if len(lst) == 1:
      return lst
   else:
      head,tail=lst
      return [head] + foo(tail)
            



if __name__ =='__main__':
    a =['a', ['b', ['c']]]
    print foo(a)
aber ich denke das ist nicht die einfachste weg.

Grüßen
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Donnerstag 13. November 2008, 12:05

Sieht doch ganz gut aus. Du könntest die Funktion höchstens noch etwas aufmotzen, indem du sie flexibler machst. Schau mal hier vorbei. Da ist eine schöne, flexiblere Lösung zu finden.
lunar

Donnerstag 13. November 2008, 12:07

Naja, es ist rekursiv, was in Python aufgrund des Rekursionslimits immer ein bisschen blöd ist. Eine iterative Implementierung wäre besser.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Donnerstag 13. November 2008, 13:40

lunar hat geschrieben:Naja, es ist rekursiv, was in Python aufgrund des Rekursionslimits immer ein bisschen blöd ist. Eine iterative Implementierung wäre besser.
Gut, aber das würde ich schon von der Aufgabe abhängig machen. Sonst würde ich das ganze so lösen:

Code: Alles auswählen

def flatten(list_):
    for idx, elem in enumerate(list_):
        next_idx = idx + 1
        try:
            next_elem = list_[next_idx]
        except IndexError:
            pass
        else:
            del list_[next_idx]
            list_.extend(next_elem)


if __name__ == '__main__':
    foo = [1, [2, [3, [4]]]]
    flatten(foo)
    print foo
Gruß,
Manuel
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Donnerstag 13. November 2008, 13:58

"flattening lists" ist das Stichwort.

Die Doku des `itertools`-Moduls hält folgendes Rezept bereit:

Code: Alles auswählen

def flatten(list_of_lists):
    return list(chain.from_iterable(list_of_lists))
`from_iterable` wurde allerdings erst jüngst mit Python 2.6 eingeführt.

In der Doku von Python 2.5.2 sieht das Rezept noch so aus:

Code: Alles auswählen

def flatten(list_of_lists):
    return list(chain(*list_of_lists))
Interessanterweise resultiert das bei mir allerdings in den Fehler "TypeError: chain argument #1 must support iteration". Dagegen funktioniert es, wenn ich es so definiere:

Code: Alles auswählen

def flatten(list_of_lists):
    return list(chain(*[list_of_lists]))
Sollte so ein Bug(?) nachträglich in der älteren Doku-Version korrigiert werden? Hat ja sicher auch noch einige Leser. Bei der Gelegenheit könnte man gleich den (von mir hier bereits umbenannten) unpythonischen Namen `listOfLists` ändern :)


->

Code: Alles auswählen

In [20]: x = [1, [2, [3, [4, 5]]]]

In [21]: flatten(x)
Out[21]: [1, [2, [3, [4, 5]]]]
Edit: Moment, irgendwas stimmt hier nicht ...

Ah, mein Fehler. Mit der eigentlichen 2.5.2-Version klappt dieses:

Code: Alles auswählen

In [25]: flatten([[1, 2, 3], [4], [5, 6]])
Out[25]: [1, 2, 3, 4, 5, 6]
Wie der Name schon sagt, lässt sich das auf Listen von Listen anwenden; `[1, [2, [3, 4]]]` ist aber keine Liste von Listen, zumindest was `1` betrifft.
Benutzeravatar
name
User
Beiträge: 254
Registriert: Dienstag 5. September 2006, 16:35
Wohnort: Wien
Kontaktdaten:

Donnerstag 13. November 2008, 14:27

Y0Gi hat geschrieben:

Code: Alles auswählen

def flatten(list_of_lists):
    return list(chain(*[list_of_lists]))
Das ist aber sehr suboptimal, da es mehrere verschachtelte listen nicht flattened.
Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Donnerstag 13. November 2008, 15:58

Warum hat noch keiner den Link zum Wiki gepostet?
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Donnerstag 13. November 2008, 16:51

"*(foo,)" oder "*[foo]" ist aquivalent zu "foo".

Der TypeError kommt vom ersten Element der Liste, das als Integer keine Iterierung unterstützt.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Donnerstag 13. November 2008, 17:53

So, das hat mir jetzt keine Ruhe gelassen :? :

Code: Alles auswählen

from collections import deque

def smash_down(list_):
    q = deque(list_)
    result = list()
    while q:
        data = q.popleft()
        if hasattr(data, "__iter__") and not isinstance(data, basestring):
            data = list(reversed(list(data)))
            q.extendleft(data)
        else:
            result.append(data)
    return result


if __name__ == '__main__':
    foo = [[['a', ('foo', 'bar'), 'b'], 'c'], 1, [iter(['x', 'y', 'z']), 99], [2, 'asdf', [3, ([4],)]]]
    print smash_down(foo)
    foo = [1, [2, [3]]]
    print smash_down(foo)
:twisted:
lunar

Donnerstag 13. November 2008, 17:59

Nicht alles, was iterable ist, hat eine __iter__-Methode.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Donnerstag 13. November 2008, 18:03

str1442 hat geschrieben:Der TypeError kommt vom ersten Element der Liste, das als Integer keine Iterierung unterstützt.
Klar; ich hatte übersehen, dass das `flatten`-Rezept nicht für den hier gewünschten Zweck geeignet/gedacht ist.
str1442 hat geschrieben:"*(foo,)" oder "*[foo]" ist aquivalent zu "foo".
Das kann ich so nicht stehen lassen. Mit dem Asterisk wird die folgende Sequenz quasi aufgelöst und ihre Elemente einzeln weitergegeben. Das ist im Zusammenhang mit Callable-Aufrufen sinnvoll, weil man dann eine Liste wie eine Liste von Argumenten für eine Callable verwenden kann. Analog gilt das für dicts und Keyword-Argumente.

Beispiel:

Code: Alles auswählen

def foo(*args, **kwargs):
    print args
    print kwargs

>>> a = [1, 2, 3]
>>> b = {'a': 1, 'b': 2}

>>> foo(a)
([1, 2, 3],)
{}

>>> foo(b)
({'a': 1, 'b': 2},)
{}

>>> foo(*a)
(1, 2, 3)
{}

>>> foo(*b)
('a', 'b')
{}

>>> foo(**b)
()
{'a': 1, 'b': 2}
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Donnerstag 13. November 2008, 18:06

lunar hat geschrieben:Nicht alles, was iterable ist, hat eine __iter__-Methode.
:? Könnte man das dann so erschlagen?

Code: Alles auswählen

from collections import deque

def smash_down(list_):
    q = deque(list_)
    result = list()
    while q:
        data = q.popleft()
        try:
            iter(data)
            iterable = True
        except TypeError:
            iterable = False
        if iterable and not isinstance(data, basestring):
            data = list(reversed(list(data)))
            q.extendleft(data)
        else:
            result.append(data)
    return result
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Donnerstag 13. November 2008, 18:09

@Y0Gi

?

Code: Alles auswählen

In [1]: def f(element): print element
   ...: 

In [2]: f(*("Dummy",))
Dummy

In [3]: f(*["Dummy"])
Dummy
*("Dummy",) == "Dummy".

Was die Sternchen machen, weiß ich ;)
Antworten