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

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

Moin,

wie wäre denn Dein Ansatz?

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

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

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

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

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

"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:

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

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

"*(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

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

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

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

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

@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 ;)
Benutzeravatar
name
User
Beiträge: 254
Registriert: Dienstag 5. September 2006, 16:35
Wohnort: Wien
Kontaktdaten:

str1442 hat geschrieben:@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 ;)
Aua! Sie geben von der liste jeweils ein element als ein argument zur Funktion.
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.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

:roll:

Ja, ich *weiß* was sie tun.

Code: Alles auswählen

    return list(chain(*[list_of_lists]))
Und wo ist das hier bitte sinnvoll angewandt?.

>>> from itertools import chain
>>> list(chain(range(3), range(3, 7)))
[0, 1, 2, 3, 4, 5, 6]
>>> list(chain(*[range(3), range(3, 7)]))
[0, 1, 2, 3, 4, 5, 6]
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

str1442: Ah, ich glaube mir ist klar, warum du diesen speziellen Fall genannt hast. Die Sternchen-Syntax hatte ich nur fürs allgemeine Verständnis mal ausgeführt.

Fakt ist ja, wie ich schon schrieb, dass das `itertools`-`flatten`-Rezept nicht für diesen Anwendungsfall passt und daher auch nicht mit der Eingabe umgehen kann. Ich hatte mich auch nicht darüber gewundert, wo der "Fehler" liegt (den ich ja "behoben" habe), sondern war eben überrascht, dass `flatten` nicht mit nicht-Listen als Elemente der äußeren Liste umgehen kann.
Antworten