mitmario.dev

Mengen

Python Sandbox 3 Min Lesezeit 5 BeispieleLektion 6 von 7

Doppelte von einem Einkaufszettel holen hieß bisher, für jeden Eintrag mit in zu fragen, ob er schon auf der neuen Liste steht, und ihn nur dann anzuhängen. Das funktioniert, und du siehst dabei, was passiert. Es ist aber viel Code für eine Frage, die man ständig hat. Was kommt hier vor, jedes nur einmal? Schon dort stand deshalb ein Versprechen, nämlich eine eigene Sorte Sammlung für diesen Zweck.

Jeder Wert nur einmal

Jeder Wert nur einmal
zettel = ["Milch", "Brot", "Milch", "Eier", "Brot", "Milch"]
sachen = set(zettel)
print(len(zettel), len(sachen))
print(sorted(sachen))
print("Eier" in sachen)

Das ist die Menge (set). set(zettel) macht aus der Liste eine Menge, und in einer Menge kommt jeder Wert genau einmal vor, egal wie oft er in der Liste stand. Aus sechs Einträgen werden drei Sachen.

len() zählt sie, in fragt, ob etwas dabei ist, und sorted() macht daraus wieder eine Liste, sortiert. Geschrieben wird eine Menge in geschweiften Klammern wie ein Dictionary, nur ohne Doppelpunkte, also ohne Werte, etwa {"Brot", "Milch"}.

Nach einer Position kannst du eine Menge nicht fragen. sachen[0] gibt TypeError: 'set' object is not subscriptable, auf Deutsch etwa „eine Menge hat keine nummerierten Plätze“. Das liegt an der wichtigsten Eigenschaft einer Menge.

Ohne Reihenfolge, wirklich

Ohne Reihenfolge
sachen = {"Brot", "Milch", "Eier", "Käse"}
print(sachen)
print(sorted(sachen))
print({3, 1, 2})
print({10, 3, 100})

Eine Menge hat keine Reihenfolge. Nicht die des Hineinkommens wie ein Dictionary und nicht die des Alphabets. Gar keine. Dieselbe Menge kam in einem Lauf als {'Käse', 'Milch', 'Brot', 'Eier'} heraus und im nächsten als {'Milch', 'Käse', 'Eier', 'Brot'}. Wenn du das Beispiel ein paarmal laufen lässt, sieht die erste Zeile immer wieder anders aus, die zweite nie.

In diesem Kurs wird eine Menge deshalb immer mit sorted() sortiert, bevor sie ausgegeben wird. Sonst steht bei jedem Lauf etwas anderes da. Eine Ausgabe, die du prüfen oder mit der von gestern vergleichen willst, ist dann nichts wert.

Die beiden Zeilen mit Zahlen sind eine Falle für alle, die gern mit kleinen Zahlen ausprobieren. {3, 1, 2} kommt als {1, 2, 3} heraus und sieht sortiert aus. {10, 3, 100} bleibt dagegen {10, 3, 100}. Das Sortierte war ein Zufall der Bauweise und keine Zusage.

Zwei Mengen vergleichen

Zwei Zettel vergleichen
mia = {"Brot", "Milch", "Eier", "Kaffee"}
ole = {"Milch", "Kaffee", "Bananen"}
print(sorted(mia & ole))
print(sorted(mia | ole))
print(sorted(mia - ole))
print(sorted(ole - mia))

Am nützlichsten sind Mengen, wenn du zwei davon vergleichst. Mia und Ole haben jeder einen Einkaufszettel geschrieben, und mit drei Zeichen bekommst du drei Antworten.

  • mia & ole ist die Schnittmenge (intersection), also was auf beiden Zetteln steht.
  • mia | ole ist die Vereinigung (union), also alles, was auf irgendeinem steht, jedes nur einmal.
  • mia - ole ist die Differenz (difference), also was auf Mias Zettel steht und nicht auf Oles.

Bei der Differenz kommt es auf die Reihenfolge an. ole - mia ist etwas ganz anderes, nämlich nur die Bananen. Mit Listen ginge das alles auch, mit Schleifen, in und Geduld. Mit Mengen ist es ein Zeichen.

Die leere Menge

Eine leere Menge
leer = {}
print(type(leer))
gaeste = set()
print(type(gaeste), len(gaeste))
gaeste.add("Mia")
gaeste.add("Ole")
gaeste.add("Mia")
print(sorted(gaeste))

In der Schreibweise steckt eine Falle. Zwei geschweifte Klammern ohne Inhalt ergeben ein leeres Dictionary und keine leere Menge, weil das Dictionary in Python zuerst da war. Eine leere Menge bekommst du mit set(). Hinzugefügt wird mit add (hinzufügen), und wer zweimal Mia hinzufügt, hat trotzdem nur eine Mia.

Wenn du {} schreibst und danach add aufrufst, gibt es einen AttributeError, in dem das Wort dict steht. Dann ist gar keine Menge da. Ändern musst du die Zeile, in der sie entstehen sollte.

Der Zettel aus Lektion 6.5

Der Zettel aus Lektion 6.5
eintraege = ["Milch", "eier", "Brot", "brot", "Kaffee",
             "milch", "Eier", "Bananen"]
sachen = set([eintrag.title() for eintrag in eintraege])
for nummer, sache in enumerate(sorted(sachen), start=1):
    print(f"{nummer}. {sache}")

Hier ist der versprochene kürzere Weg. Die List Comprehension schreibt alle Einträge gleich, set() wirft die Doppelten weg, und mit sorted() und enumerate wird der Zettel daraus. Auf die Reihenfolge der Schritte kommt es dabei genauso an wie beim ersten Mal. Erst wird alles gleich geschrieben, dann kommt es in die Menge. Andersherum blieben Milch und milch zwei verschiedene Sachen, und die Menge hätte nichts zu tun.

Was die Aufgabe will

Ein Verein hatte zwei Termine, ein Sommerfest und einen Arbeitseinsatz, und für beide gibt es eine Liste, wer da war. Auf beiden haben sich Leute zweimal eingetragen. Gesucht ist, wer bei beiden war, wer nur beim Sommerfest und wie viele verschiedene Leute es insgesamt waren.

Zum Mitnehmen

In einer Menge (set) steht jeder Wert nur einmal, und auf ihre Reihenfolge ist kein Verlass. Mit set() wird aus einer Liste eine Menge ohne Doppelte. & findet, was in beiden steht, | nimmt alles zusammen und - lässt nur übrig, was in der ersten steht. Vor der Ausgabe wird sortiert.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 5 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.