Array, Dictionary und Set
Ein Array speichert Elemente in fester Reihenfolge, ein Dictionary ordnet Schlüsseln Werte zu, ein Set enthält jedes Element höchstens einmal. Alle drei sind in Swift Werttypen. Wenn du eine Collection einer neuen Variable zuweist, entsteht eine unabhängige Kopie.
Danach kannst du
- wählst die passende Collection für deine Daten
- fügst Elemente hinzu, entfernst sie und greifst sicher darauf zu
- weißt, warum Dictionary-Zugriffe ein Optional liefern
- vermeidest Abstürze durch ungültige Indizes
Voraussetzungen
Umgebung
Swift 6.4.0, Sprachmodus 6
plattformunabhängig, geprüft unter Linux x86-64
Auf dieser Seite
Welche Collection wofür
| Du brauchst … | Nimm | Typ geschrieben |
|---|---|---|
| eine Liste in fester Reihenfolge, Duplikate erlaubt | Array | [String] |
| Werte, die du über einen Schlüssel findest | Dictionary | [String: Int] |
| eine Menge ohne Duplikate, schnelle Prüfung „ist enthalten?“ | Set | Set<String> |
Alle drei Typen speichern nur Elemente eines Typs. Ein [String] kann keine Zahl enthalten. Wenn du gemischte Daten zusammenfassen willst, ist meist ein eigener struct die bessere Wahl; mehr dazu in der Lektion zu Structs, Klassen und Enums.
Arrays
var einkauf = ["Brot", "Milch", "Äpfel"]
einkauf.append("Kaffee")
einkauf.insert("Butter", at: 1)
einkauf.remove(at: 0)
print(einkauf)
print("Anzahl:", einkauf.count)
print("Erstes:", einkauf.first ?? "keins")
print("Enthält Milch?", einkauf.contains("Milch"))
// Arrays sind Werttypen: die Kopie ändert das Original nicht
var kopie = einkauf
kopie.append("Tee")
print(einkauf.count, kopie.count)
let sortiert = einkauf.sorted()
print(sortiert)
Ausgabe
["Butter", "Milch", "Äpfel", "Kaffee"] Anzahl: 4 Erstes: Butter Enthält Milch? true 4 5 ["Butter", "Kaffee", "Milch", "Äpfel"]
Zwei Dinge fallen in der Ausgabe auf.
Erstens die Kopie: kopie hat fünf Elemente, einkauf weiterhin vier. Arrays sind in Swift Werttypen. Eine Zuweisung erzeugt eine eigenständige Kopie, und Änderungen an der einen betreffen die andere nicht. Swift kopiert dabei nicht sofort Speicher, sondern erst, wenn eine der beiden Kopien tatsächlich geändert wird. Die einfache Regel für dich bleibt: Es verhält sich wie eine Kopie.
Zweitens die Sortierung: „Äpfel“ landet hinter „Milch“. sorted() vergleicht Zeichenketten nach ihren Unicode-Werten, nicht nach deutschem Alphabet, und das Ä liegt dort hinter allen Buchstaben von A bis Z. Für eine Sortierung, wie sie Menschen erwarten, brauchst du sprachabhängige Vergleiche aus Foundation, etwa localizedStandardCompare. Für interne Listen, Schlüssel oder Tests ist der einfache Vergleich dagegen genau richtig, denn er ist auf jedem System gleich.
first liefert übrigens ein Optional: Ein leeres Array hat kein erstes Element. Deshalb steht dort ?? "keins".
Ungültige Indizes
Der Zugriff mit eckigen Klammern prüft den Index zur Laufzeit. Ist er ungültig, bricht das Programm ab:
let tage = ["Mo", "Di", "Mi"]
print(tage[3])
Abbruch zur Laufzeit
Swift/ContiguousArrayBuffer.swift:695: Fatal error: Index out of range
Ein Array mit drei Elementen hat die Indizes 0, 1 und 2. Gegen diesen Absturz helfen first, last und indices.contains(i), oder du läufst mit for über die Elemente selbst statt über Indizes.
Dictionaries
var lager = ["Äpfel": 12, "Birnen": 4, "Kiwis": 30]
lager["Mangos"] = 7
// Der Zugriff liefert ein Optional, denn der Schlüssel kann fehlen
if let aepfel = lager["Äpfel"] {
print("Äpfel:", aepfel)
}
print("Pflaumen:", lager["Pflaumen"] ?? 0)
// Standardwert direkt beim Zugriff
var zaehler: [String: Int] = [:]
for wort in ["swift", "lernen", "swift"] {
zaehler[wort, default: 0] += 1
}
print(zaehler["swift"]!, zaehler["lernen"]!)
// Dictionaries haben keine feste Reihenfolge, also vor der Ausgabe sortieren
for (sorte, menge) in lager.sorted(by: { $0.value > $1.value }) {
print(sorte, menge)
}
Ausgabe
Äpfel: 12 Pflaumen: 0 2 1 Kiwis 30 Äpfel 12 Mangos 7 Birnen 4
Ein Dictionary-Zugriff liefert immer ein Optional, denn der Schlüssel kann fehlen. Statt abzustürzen wie ein Array liefert lager["Pflaumen"] einfach nil. Du entscheidest dann mit if let oder ??, was passieren soll.
zaehler[wort, default: 0] += 1 ist das Standardmuster zum Zählen: Gibt es den Schlüssel noch nicht, startet die Zählung bei 0.
Die Reihenfolge der Einträge in einem Dictionary ist nicht festgelegt und kann sich zwischen zwei Programmläufen unterscheiden. Für eine stabile Ausgabe sortierst du vorher, wie im Beispiel mit sorted(by:). Den Ausdruck in den geschweiften Klammern erklärt die nächste Lektion zu Closures.
Sets
let anna: Set = ["Swift", "Python", "Rust"]
let ben: Set = ["Swift", "Kotlin"]
print(anna.contains("Rust"))
print(anna.intersection(ben).sorted()) // beide
print(anna.union(ben).sorted()) // zusammen
print(anna.subtracting(ben).sorted()) // nur Anna
// Doppelte Einträge verschwinden
let eingaben = ["a", "b", "a", "c", "b"]
print(Set(eingaben).count)
Ausgabe
true ["Swift"] ["Kotlin", "Python", "Rust", "Swift"] ["Python", "Rust"] 3
Ein Set beantwortet die Frage „ist dieses Element enthalten?“ im Durchschnitt gleich schnell, egal wie groß es ist. Bei einem Array muss Swift dafür im schlechtesten Fall jedes Element ansehen. Dazu kommen die Mengenoperationen: Schnittmenge, Vereinigung und Differenz. Wie Dictionaries haben Sets keine feste Reihenfolge, deshalb wird hier vor der Ausgabe sortiert.
Elemente eines Sets und Schlüssel eines Dictionaries müssen das Protokoll Hashable erfüllen. Alle Grundtypen wie String, Int und Double tun das. Für eigene Typen kannst du es meist einfach dazuschreiben.
Häufige Fehler
Fatal error: Index out of range. Index zu groß oder negativ. Prüfe mit indices.contains(i) oder vermeide Indizes.
value of optional type 'Int?' must be unwrapped beim Dictionary-Zugriff. Der Wert kann fehlen. Entpacke ihn mit if let oder gib mit ?? einen Ersatzwert an.
Eine Ausgabe ändert ihre Reihenfolge von Lauf zu Lauf. Du gibst ein Dictionary oder ein Set direkt aus. Sortiere vorher.
Übungen
- Lege ein Array mit fünf Noten (
Intvon 1 bis 6) an. Berechne den Durchschnitt alsDoubleund zähle mit einem Dictionary, wie oft jede Note vorkommt. Gib die Zählung sortiert nach Note aus. - Gegeben sind zwei Arrays mit Teilnehmenden von zwei Kursen. Gib aus, wer in beiden Kursen ist, sortiert und ohne Duplikate.
Lösung zu Übung 1
let noten = [2, 1, 3, 2, 4]
let durchschnitt = Double(noten.reduce(0, +)) / Double(noten.count)
print("Durchschnitt:", durchschnitt)
var haeufigkeit: [Int: Int] = [:]
for note in noten {
haeufigkeit[note, default: 0] += 1
}
for (note, anzahl) in haeufigkeit.sorted(by: { $0.key < $1.key }) {
print("Note \(note): \(anzahl)×")
}
Ausgabe
Durchschnitt: 2.4 Note 1: 1× Note 2: 2× Note 3: 1× Note 4: 1×
Lösung zu Übung 2
let kursA = ["Lena", "Tom", "Ada", "Tom", "Mia"]
let kursB = ["Mia", "Jonas", "Lena"]
let inBeiden = Set(kursA).intersection(kursB).sorted()
print(inBeiden)
Ausgabe
["Lena", "Mia"]
Aus den Arrays werden Sets, dann bleibt nur die Schnittmenge übrig, und sorted() macht daraus wieder ein Array in fester Reihenfolge.