List Magic

Head, Tail

Altes Problem, geht man zumeist so an:

>>> l = list(range(10))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> head, tail = l[0], l[1:]
>>> head
0
>>> tail
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Nach PEP 3132 wird das alles viel eleganter:

>>> head, *tail = list(range(10))
>>> head
0
>>> tail
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Was noch so geht

Zum Beispiel beim Iterieren über eine Liste von Tupeln das letzte Element extra behandeln:

>>> l = list((x, x+x, x*x) for x in range(5))
>>> l
[(0, 0, 0), (1, 2, 1), (2, 4, 4), (3, 6, 9), (4, 8, 16)]
>>> for *head, last in l:
...     print(last, '->', head)
...
0 -> [0, 0]
1 -> [1, 2]
4 -> [2, 4]
9 -> [3, 6]
16 -> [4, 8]

Flatten

Verschachtelte Listen lassen sich durch eine List-Comprehension auflösen:

>>> ll = [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> [fl for at in ll for fl in at]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Das ganze ist aber nicht Speichereffizient. Wenn man über die Elemente in den Listen der Liste iterieren muss, greift man auf die itertools zurück:

>>> from itertools import chain
>>> ll = [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> cl = chain.from_iterable(ll)
>>> cl
<itertools.chain object at 0x10a8b5b00>
>>> for c in cl:
...     print(c)
...
0
1
2
[...]

Achtung. Es handelt sich hier um einen Iterator. Wenn versucht wird mehrmals darüber zu iterieren, wird das nichts.

>>> ll = [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> cl = chain.from_iterable(ll)
>>> list(cl)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(cl)
[]

Verschachtelt iterieren

Das ganze lässt sich aber auch dazu nutzen, mehrere for-loops abzukürzen:

>>> res = []
>>> for x in [0, 1, 2, 3, 4]:
...     for y in [5, 6, 7, 8, 9]:
...         res.append((x, y, x+y, x*y))
>>> res
[(0, 5, 5, 0), (0, 6, 6, 0), (0, 7, 7, 0), ...]

… wird somit zu:

>>> nres = [(x, y, x+y, x*y) for x in [0, 1, 2, 3, 4] for y in [5, 6, 7, 8, 9]]
>>> nres
[(0, 5, 5, 0), (0, 6, 6, 0), (0, 7, 7, 0), ...]
>>> assert res == nres