Aufgaben-Python/g09_dictionaries_und_sets/README.md

169 lines
6.5 KiB
Markdown

# Kapitel G09: Dictionaries & Sets (Mengen) 📖🎯
Schulabgleich: **Thema 15.0 (Dictionaries und Mengen)**
Herzlich willkommen zu Kapitel G09! In diesem Kapitel lernst du zwei unverzichtbare Datenstrukturen kennen, die in modernen Python-Programmen tagtäglich eingesetzt werden: **Dictionaries** (Schlüssel-Wert-Zuordnungen) und **Sets** (Mengen ohne Duplikate).
---
## 🗃️ 1. Dictionaries: Die Karteikasten-Analogie
Ein **Dictionary** (abgekürzt `dict`) speichert Daten als **Schlüssel-Wert-Paare** (`key: value`).
Stell dir einen klassischen **Karteikasten** oder ein **Wörterbuch** vor:
- Wenn du nach dem Wort *"Schmetterling"* suchst (der **Key / Schlüssel**), findest du die englische Übersetzung *"Butterfly"* (der **Value / Wert**).
- Während eine Python-Liste Elemente über einen numerischen Index (`liste[0]`, `liste[1]`) abruft, greift ein Dictionary über beliebige eindeutige Schlüssel (meist Texte oder Zahlen) zu!
```
[ DICTIONARY: telefonbuch ]
┌────────────────────────┬────────────────────────┐
│ SCHLÜSSEL (Key) │ WERT (Value) │
├────────────────────────┼────────────────────────┤
│ "Anna" │ "0171-123456" │
│ "Ben" │ "0160-987654" │
│ "Clara" │ "0151-555666" │
└────────────────────────┴────────────────────────┘
```
### Grundlegende Syntax:
```python
# Dictionary erstellen:
kontakt = {
"name": "Anna",
"alter": 23,
"ort": "Berlin"
}
# Zugriff über Schlüssel:
print(kontakt["name"]) # "Anna"
# Neuen Eintrag hinzufügen oder bestehenden ändern:
kontakt["email"] = "anna@example.com"
kontakt["alter"] = 24
# Eintrag entfernen:
del kontakt["ort"]
# oder mit Rückgabewert:
entfernter_wert = kontakt.pop("email")
```
---
## 🛡️ 2. Sicherer Datenzugriff: `dict[key]` vs. `dict.get(key, default)`
Ein häufiger Absturzgrund in Python ist der direkte Zugriff auf einen nicht existierenden Schlüssel:
```python
benutzer = {"name": "Max"}
# 💥 ABSTURZ:
print(benutzer["telefon"]) # KeyError: 'telefon'
# ✅ SICHER:
telefon = benutzer.get("telefon", "Keine Nummer hinterlegt")
print(telefon) # Gibt "Keine Nummer hinterlegt" aus, OHNE Absturz!
```
> **Goldene Regel:** Wenn du nicht zu 100% sicher bist, ob ein Schlüssel im Dictionary vorkommt, nutze immer `.get()` mit einem sinnvollen Standardwert!
---
## 🔄 3. Über Dictionaries iterieren: `.keys()`, `.values()`, `.items()`
Python bietet drei praktische Methoden für Schleifen:
```python
preise = {"Apfel": 0.80, "Banane": 1.20, "Mango": 2.50}
# 1. Nur Schlüssel durchlaufen:
for frucht in preise.keys(): # oder einfach: for frucht in preise:
print(frucht)
# 2. Nur Werte durchlaufen:
for preis in preise.values():
print(f"{preis:.2f} €")
# 3. Schlüssel UND Werte gleichzeitig (sehr nützlich!):
for frucht, preis in preise.items():
print(f"{frucht}: {preis:.2f} €")
```
---
## 🎟️ 4. Sets (Mengen): Die Club-Türsteher-Analogie
Ein **Set** (`set`) ist eine ungeordnete Sammlung von **eindeutigen Elementen**.
Stell dir einen strengen **Club-Türsteher** vor:
- Jeder Gast darf nur **ein einziges Mal** auf die Gästeliste.
- Wenn jemand versucht, sich ein zweites Mal anzustellen, winkt der Türsteher ab: *"Du bist schon drin!"*
- Im Club gibt es **keine feste Reihenfolge** (Sets haben keinen Index `set[0]`).
```python
# Set mit geschweiften Klammern erstellen:
farben = {"rot", "grün", "blau", "rot", "grün"}
print(farben) # Ausgabe: {'rot', 'blau', 'grün'} (Duplikate automatisch entfernt!)
# Schnelle Zugehörigkeitsprüfung mit 'in' (extrem schnell in O(1)):
if "rot" in farben:
print("Rot ist dabei!")
```
---
## 🧮 5. Mathematische Mengenoperationen mit Sets
Sets glänzen bei mathematischen Mengen-Vergleichen:
| Operation | Operator | Methode | Beschreibung |
| :--- | :--- | :--- | :--- |
| **Schnittmenge** | `A & B` | `A.intersection(B)` | Elemente, die in **beiden** Mengen vorkommen |
| **Vereinigung** | `A \| B` | `A.union(B)` | Alle Elemente aus **beiden** Mengen (ohne Duplikate) |
| **Differenz** | `A - B` | `A.difference(B)` | Elemente, die in A, aber **nicht** in B sind |
| **Symmetrische Differenz** | `A ^ B` | `A.symmetric_difference(B)` | Elemente in A oder B, aber **nicht in beiden** |
```python
schueler_kurs_a = {"Anna", "Ben", "Clara"}
schueler_kurs_b = {"Ben", "Daniel", "Clara", "Emma"}
# Wer ist in beiden Kursen? (Schnittmenge)
beide = schueler_kurs_a & schueler_kurs_b
print("In beiden Kursen:", beide) # {'Ben', 'Clara'}
# Alle Schüler insgesamt? (Vereinigung)
alle = schueler_kurs_a | schueler_kurs_b
print("Alle Schüler:", alle) # {'Anna', 'Ben', 'Clara', 'Daniel', 'Emma'}
# Wer ist nur in Kurs A? (Differenz)
nur_a = schueler_kurs_a - schueler_kurs_b
print("Nur in Kurs A:", nur_a) # {'Anna'}
```
---
## ⚠️ Häufige Stolperfallen
1. **Leeres Set vs. Leeres Dictionary:**
- `{}` erzeugt ein **leeres Dictionary**, KEIN Set!
- Um ein leeres Set zu erstellen, schreibe immer: `mein_set = set()`.
2. **Keine veränderlichen Typen (Lists) als Keys oder Set-Elemente:**
- Dictionaries-Schlüssel und Set-Elemente müssen **hashbar** (unveränderlich) sein (Strings, Zahlen, Tuples). Listen `[1, 2]` sind verboten (`TypeError: unhashable type: 'list'`).
3. **Reihenfolge bei Sets:**
- Sets garantieren **keine** feste Reihenfolge. Wenn du Duplikate aus einer Liste entfernen und dabei die Reihenfolge beibehalten willst, musst du dir mit einer Hilfsmenge (`seen = set()`) und einer Ergebnisliste behelfen.
---
## 🎯 Deine Aufgaben in `aufgabe.py`
Öffne `g09_dictionaries_und_sets/aufgabe.py` und implementiere:
1. **TODO 1 (`woerter_haeufigkeit`):** Zähle die Häufigkeit jedes Wortes in einem Text (in Kleinbuchstaben, ohne Satzzeichen).
2. **TODO 2 (`telefonbuch_suche`):** Suche sicher mit `.get()` eine Nummer im Telefonbuch (Rückgabe: Nummer oder `"Nicht gefunden"`).
3. **TODO 3 (`gemeinsame_interessen`):** Finde die Hobbys, die zwei Personen gemeinsam haben (Schnittmenge `&`).
4. **TODO 4 (`entferne_duplikate_behalte_reihenfolge`):** Filtere Duplikate aus einer Liste, behalte die Reihenfolge des ersten Auftretens bei.
### Testen:
```bash
python3 test_aufgabe.py
```
Sobald alle 9 Tests mit `OK` durchlaufen, bist du bereit für Kapitel G10!