7. Listen, Tupel, Sets und Dictionaries

In den letzten Kapiteln habe ich Ihnen gezeigt, wie Sie mit Zeichenketten, Zahlen und Datumswerten umgeben. Aber wie müssen Sie vorgehen, wenn Sie mehrere gleichartige Daten verarbeiten müssen, z.B. 100 Messdaten, 10.000 eMail Adressen oder ähnliches?

Python enthält im Sprachkern diverse Datentypen, die zur Verwaltung von Aufzählungen verwendet werden können.

Listen: Eigentlich der wichtigste Datentyp zur Speicherung einer variablen Auswahl von Elementen. Die Ordnung der darin enthaltenen Elemente bleibt erhalten, es können jederzeit und an jeder Stelle Elemente hinzugefügt werden.

Tupel (Sequenzen): Vereinfacht gesprochen sind Tupel eine unveränderliche Liste mit wenigen Elementen. Tupel ind in Ihren Möglichkeiten wesentlich simpler als Listen, intern aber auch mit weniger Overhead verbunden. Dadurch werden Sie oft verwendet um mehrere Daten an Funktionen zu übergeben oder als Ergebnisse zurückzugeben.

Sets (Mengen): Ein Set ist eine Menge von ungeordneten Elementen ohne Doppelgänger.

Dictionaries: In Dictonaries werden Wertepaare (bestehend aus Key und Value) gespeichert. Der wesentliche Unterschied zu Listen besteht darin, das auf einzelne Werte mittels des Keys erfolgt und nicht über einen durchlaufenden Index.

Array: Arrays, die man aus anderen Programmiersprachen kennt, spielen in Python eher eine untergeordnete Rolle. Arrays können als alternative zu Listen eingesetzt werden, sofern die Anzahl der Elemente vorab bekannt sind. Arrays sind nicht so flexibel wie Listen, dafür aber bei vielen Elementen effizienter.

7.1. Listen

Ein Vorteil von Listen ist, das Sie jeden beliebigen Datentyp aufnehmen kann und werden mit eckigen Klammern formuliert. Ein Zugriff auf die einzelnen Elemente erfolgt wie auf die Zeichen einer Zeichenkette, also in Form liste[start:ende]. Vergessen Sie nicht, das bei Python die Nummerierung immer bei 0 beginnt und das die Startposition inklusive, die Endposition aber exklusive ist.

lst = [1, 2.3, 'abc', 'efg', 12]
lst[2]                              # das dritte Element 'abc'

lst[2:4]                            # vom dritten bis zum vierten Element ['abc', 'efg']

lst[::-1]                           # umgekehrte Reihenfolge [12, 'efg', 'abc', 2, 1]

lst[0] = 3                          # ändert das erste Listenelement
print(lst)                          # Ausgabe: [3, 2.3, 'abc', 'efg', 12]

Vorsicht

Der Versuch auf ein nicht vorhandenes Element zuzugreifen, endet mit dem Fehler list index out of range. Das wäre z.B. der Fall, wenn Sie auf der obrigen Liste lst[5] zugreifen wollen. Die Liste hat zwar fünf Elemente, aber da die Zählung mit 0 beginnt, erfolgt der korrekte Zugriff auf das letzte Element mit lst[4] oder mit lst[-1].

Da Listen jedes beliebe Python Objekt als Listenelement aufnehmen kann, sind auch verschachtelte Listen zulässig. Entsprechend sind beim Auslesen der Elemente oft mehrere hintereinandergestellte Klammerpaare erfolderlich.

lst = [[1, 2], [3, 4]]              # verschachtelte Liste
lst[0]                              # das erste Element ist selbst eine Liste [1, 2]
lst[0][1]                           # das zweite Element der ersten Teilliste 2                       

7.1.1. range Funktion

Mit der Funktion list(range(start, ende, schrittweise)) erzeugen Sie unkompliziert Listen die Zahlen in einem bestimmten Wertebereich liegen. Damit eine Liste, bestehend aus Zehnerzahlen (10, 20,…) mit einem Wert 100 endet, muss der Endwert grösser 100 sein.

lst = list(range(10, 101, 10))     # erzeugt eine Liste
print(lst)                         # Ausgabe: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

7.1.2. Listen und Zeichenketten

Die Zeichen einer Zeichenkette wandeln sie mit list in eine Liste um:

hwlst = list('Hello World')
print(hwlst)                       # Ausgabe: ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!']

Nicht so ganz offentsichtlich ist das Zusammenfügen der Listelemente zu einer neuen Zeichenkette. Dazu verwendet man die join Methode auf einer leeren Zeichenkette an.

''.join(hwlst)                       # Ausgabe: 'Hello World!'

Die Zeichenkette vor dem join gibt das oder die Trennzeichen zwischen den Listenelementen an.

7.1.3. List Comprehension

Python bietet viele Möglichkeiten Listenelemente zu verarbeiten. Am geeignesten finde ich die Möglichkeit der List Comprehension. Dabei werden Anweisungen in der Form [ausdruck for x in liste] gebildet. Python ersetzt nun der Reihe nach jedes Element der Liste in die Variable x und erst dann wird der Ausdruck ausgewertet. Die Ergebnisse ergeben nun eine neue Liste.

lst = list(range(10, 101, 10))
[x*2+1 for x in lst]              # Ausgabe: [21, 41, 61, 81, 101, 121, 141, 161, 181, 201]


[ [x, x*x] for x in lst]          # Ausgabe: [[10, 100], [20, 400], [30, 900], 
#                                            [40, 1600], [50, 2500], [60, 3600], [70, 4900],
#                                            [80, 6400], [90, 8100], [100, 10000]]

Es gibt viele Programmierer, die die Verarbeitung in traditionelle Schleifen lieber durchführen. Beides ist möglich und zulässig, aber meist der Weg, der nicht so effizent ist.

for x in lst:
  print(x, x*x, x**3, sep='\t')


# Ausgabe:
10         100           1000
20         400           8000
30         900           27000
40         1600          64000
50         2500          125000
60         3600          216000
70         4900          343000
90         8100          729000
100        10000         1000000

7.2. Funktionen zur Verarbeitung von Listen

Wenn es um die Manipulation von Listen geht, kennt Python eine Menge Funktionen und Methoden dazu.

len(lst)                    # ermittelt die Anzahl der Elemente

lst.extend([110])           # fügt ein Element am Ende an
                            # lst[10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110]

lst.insert(5, 55)           # fügt ein Element in der Mitte dazu
                            # lst[10, 20, 30, 40, 50, 55, 60, 70, 80, 90, 100, 110]

lst.pop(5)                  # entfernt das Element an der Position 5
                            # lst[10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110]

lst += [120, 110]           # fügt eine zweite Liste hinzu
                            # lst[10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130]

del lst[-3:]                # entfernt die letztendrei Elemente der List
                            # lst[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

lst.remove(80)              # entfernt die Zahl 80 aus der Liste
                            # lst[10, 20, 30, 40, 50, 60, 70, 90, 100, 110]
Funktion / MethodeBedeutung
del l[start:ende]Entfernt die angegebenen Listenelemente
n = len(l)Liefert die Anzahl der Elemente
l.append(x)Fügt das Element x am Ende der Liste hinzu
l.clear()Löscht die Liste (entspricht l =[])
n = l.count(x)Ermittelt, wie oft das Element x in der Liste vorkommt.
l1.extend(12)Fügt der Liste l2 am Ende von l1 hinzu (l1 += 12).
iterator = filter(f, l)Liefert die Elemente zurück, für die f(elemente) == true gilt
n = l.index(x)Ermittelt die erste Position von x in der Liste
l.insert(n, x)Fügt das Element x an der Position n in die Liste ein
iterator = map(f, l)Wendet die Funktion f auf alle Elemente an
min(l) und max(l)Ermittelt das kleinste und grösste Element
x = l.pop(n)Liest das Element an der Position n und entfernt es
l.remove(x)Entfernt das Element x aus der Liste.
l.sort()Sortiert die Liste
sum(l)Berechnet die Summe der Listenelemente
iterator = zip(11, 12)Verbindet die Listenelemente paarweise zu Tupel

Eine Referenz mit weiteren Methoden finden man hier: https://docs.python.org/3/tutorial/datastructures.html

7.2.1. map Funktion

In den nächsten Abschnitten werden wir uns mit den Funktionen map, reduce ud filter beschäfftigen. Diese sind keine ausgesprochenen Listenfunktionen. Sie können auf jedes Objekt abgewandt wander, welches iterable ist, d.h. das mehrere Elemente enthält, die über eine Schleife gebildet werden können. Ausser auf Listen trifft dies auch auf Sets, Tupel und Dictionaries zu.

map wendet eine Funktion auf alle Elemente einer Liste an und liefert aus Effizenzgründen nicht unmittelbar eine Ergebnisliste, sondern einen Iterator. Diese Objekte können Sie dann z.B. in einer Schleife auswerten oder mit list in eine Liste umwandeln.

def quad(x):
    return x*x


lst = [1, 2, 3, 4, 5]
iterator = map(quad, lst)        # map liefert einen Iterator
list(iterator)                   # list(...) liefert eine Liste
                                 # Ausgabe: [1, 4, 9, 16, 25]

Funktionen

Im obrigen Beispiel wurde mit quad eine einfache Funktion definiert, die den übergebenen Paramater quadriert und das Ergebnis zurückgibt.

Es ist nicht notwendig die Funktion, die sie an map übergeben zuerst mit def zu definieren. Sie können die Funktion auch ad hoc als Lambda Funktion angeben. Dabei verwenden Sie das Schlüsselwort lambda um zuerst einen Variablennamen und dann die Funktion für die Variable angeben.

list(map(lambda x: x*x, lst))    # Ausgabe: [1, 4, 9, 16, 25]

Diese gewünschte Ausgaben lässt sich syntaktisch noch verkürzen und eleganter formulieren. Anstelle von map können Sie auch die brêreits erwähnte List Comprehension einsetzen. Dazu plaziert man die for Schleife in eine eckigen Klammer einer Liste.

[ x*x for x in l ]                # Ausgabe: [1, 4, 9, 16, 25 ]

map kann auch mehrere Listen verarbeiten. Sind diese Listen unterschiedlich lang, so liefert map so viele Elemente wie die kürzeste Liste enthält.

def f(x, y):                      # Funktion, die wei Paramater addiert
    return x + y


lst1 = [7, 1, 4]
lst2 = [10, 11, 12]
# map wendet f auf die Daten von lst1 und lst2 an,
# list wertet den resultierenden Iterator aus
lst3 = list(map(f, lst1, lst2))
print(lst3)                        # [17, 12, 16]

7.2.2. reduce Funktion