Seite 1 von 1

Verknüpfen von Listen: Reißverschluss

Verfasst: Mittwoch 14. Oktober 2009, 11:02
von achilles_69
Hallo,

ich suche nach einer eleganten Lösung für folgendes Problem: ich habe zwei Listen und möchte die wie die beiden Hälften eines Reißverschlusses verbinden, also so

Code: Alles auswählen

list1 = ['a0', 'a1', 'a2']
list2 = ['b0', 'b1', 'b2']
dies soll also die folgende Liste ergeben:

Code: Alles auswählen

['a0', 'b0', 'a1', 'b1', 'a2', 'b2']
In meinem speziellen Fall ist sichergestellt, dass beide Listen die gleiche Anzahl von Elementen haben.
Zu einer primitiven quick'n'dirty-Version habe ich irgendwie keine Lust. Es gibt doch bestimmt eine elegante 'pythonische' Art einer Lösung...

Verfasst: Mittwoch 14. Oktober 2009, 11:12
von yipyip

Code: Alles auswählen

In [71]: list(sum(zip(list1, list2), ()))
Out[71]: ['a0', 'b0', 'a1', 'b1', 'a2', 'b2']
:wink:
yipyip

Verfasst: Mittwoch 14. Oktober 2009, 11:41
von achilles_69
Super, funktioniert. Ich liebe solche Einzeiler...

Auf zip() war ich auch schon gestoßen, aber die erzeugt mir ja eine Liste von Sets.
Auf das sum() war ich nicht gekommen, ich verstehe im Moment aber noch nicht ganz, wie sum() in diesem Zusammenhang eigentlich genau funktioniert...

Verfasst: Mittwoch 14. Oktober 2009, 12:26
von Leonidas
Persönlich bevorzuge ich ja diese Variante:

Code: Alles auswählen

from itertools import izip, chain
list(chain.from_iterable(izip(list1, list2)))
(Vermute auch, dass sie effizienter ist)

Verfasst: Mittwoch 14. Oktober 2009, 12:42
von yipyip
zip erzeugt eine Liste von Tupeln, nicht von sets.

sum summiert mit optionalem Startwert:

Code: Alles auswählen

In [97]: sum((1, 2, 3), 10)
Out[97]: 16

In [98]: sum([[1, 2, 3]], [4, 5])
Out[98]: [4, 5, 1, 2, 3]

In [99]: sum(((1, 2, 3),(4, 5)), ())
Out[99]: (1, 2, 3, 4, 5)
Listen und Tupel werden damit verkettet.

@Leonidas:
Ich nehme auch an, das die Itertools effizienter sind, aber das andere erschien mir erstmal naheliegender. (... und vertrauter...)

:wink:
yipyip

Verfasst: Mittwoch 14. Oktober 2009, 13:18
von Leonidas
yipyip hat geschrieben:Ich nehme auch an, das die Itertools effizienter sind, aber das andere erschien mir erstmal naheliegender. (... und vertrauter...)
Naja, der ``zip``/``izip``-Schritt ist in beiden Codes gleich (nur nutze ich ``izip``, weil ich keine resultierende Liste brauche, ein Iterable wie etwa ein Generator reicht auch. Du könntest auch ``izip`` nehmen, da ``sum`` damit auch zurechtkommt). Danach hat man dann eine Sequenz von 2-Tupeln. Darauf wende ich ``chain.from_iterable`` an, was einfach aus verschachtelten Iterables "flache" Iterables macht. Der letzte Schritt, dass ``list`` ist wieder gleich (nur wandelst du ein Tupel um und ich einen Generator).

Verfasst: Mittwoch 14. Oktober 2009, 13:27
von yipyip
Ich kannte zwar 'chain', aber nicht 'chain.from_iterable', das war der Knackpunkt. Jetzt werde ich's mir merken...

:wink:
yipyip

Verfasst: Mittwoch 14. Oktober 2009, 13:38
von Leonidas
yipyip hat geschrieben:Ich kannte zwar 'chain', aber nicht 'chain.from_iterable', das war der Knackpunkt.
Ja, das ist ganz neu in Python 2.6. Wie immer: wenns das nicht gäbe, müsste es erfunden werden. :)

Verfasst: Mittwoch 14. Oktober 2009, 17:06
von jbs
Leonidas hat geschrieben:
yipyip hat geschrieben:Ich kannte zwar 'chain', aber nicht 'chain.from_iterable', das war der Knackpunkt.
Ja, das ist ganz neu in Python 2.6. Wie immer: wenns das nicht gäbe, müsste es erfunden werden. :)
Oder so:

Code: Alles auswählen

from itertools import izip, chain
list(chain(*izip(list1, list2)))

Verfasst: Mittwoch 14. Oktober 2009, 17:12
von Dav1d
jbs hat geschrieben:Oder so:

Code: Alles auswählen

from itertools import izip, chain
list(chain(*izip(list1, list2)))
der * (Stern) vor izip bedeutet dass eine nicht festgelegte Anzahl von Parametern übergeben werden?

Verfasst: Mittwoch 14. Oktober 2009, 17:18
von jbs

Code: Alles auswählen

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

func(1,2,3,a=4,b=5)
func(*(1,2,3), **{'a':4,'b':5})
http://docs.python.org/dev/library/iter ... ools.chain

Verfasst: Mittwoch 14. Oktober 2009, 17:26
von Dav1d
Ah, danke, dass mit:

Code: Alles auswählen

func(*(1,2,3), **{'a':4,'b':5})
kannte ich gar nicht nur:

Code: Alles auswählen

func(1,2,3,a=4,b=5)

Verfasst: Mittwoch 14. Oktober 2009, 21:19
von DasIch
Dav1d hat geschrieben:der * (Stern) vor izip bedeutet dass eine nicht festgelegte Anzahl von Parametern übergeben werden?
Jein. Bei einem Aufruf "entpackt" ein ``*`` das folgende iterable zu mehreren Argumenten, in einer Funktionsdefinition erlaubt es beliebig viele Argumente.

Verfasst: Donnerstag 15. Oktober 2009, 01:23
von Leonidas
Also quasi das was in anderen Sprachen (und früher auch in Python) ``apply()`` gemacht hat (die Syntax mit dem Stern erinnert mich etwas an ``unquote-splicing`` in Scheme, was ähnlich funktioniert)