Kurz: let text = """ Swift ist schnell. Swift ist sicher, und Swift macht Spaß! Sicher und schnell: das ist Swift. """
Teil des Kurses Swift
Projekt 1: Wörter zählen
import Foundation
let text = """
Swift ist schnell. Swift ist sicher, und Swift macht Spaß!
Sicher und schnell: das ist Swift.
"""
let woerter = text
.lowercased()
.components(separatedBy: CharacterSet.letters.inverted)
.filter { !$0.isEmpty }
var haeufigkeit: [String: Int] = [:]
for w in woerter { haeufigkeit[w, default: 0] += 1 }
let top = haeufigkeit.sorted { ($0.value, $1.key) > ($1.value, $0.key) }.prefix(4)
print("\(woerter.count) Wörter, \(haeufigkeit.count) verschiedene")
for (w, n) in top {
print(w.padding(toLength: 8, withPad: " ", startingAt: 0), String(repeating: "#", count: n), n)
}
print("Längstes Wort:", woerter.max { $0.count < $1.count }!)Ausgabe:
16 Wörter, 8 verschiedene
swift #### 4
ist ### 3
schnell ## 2
sicher ## 2
Längstes Wort: schnellProjekt 2: Eine kleine Bank mit Protokollen und Fehlern
enum BankFehler: Error, CustomStringConvertible {
case zuWenigGuthaben(fehlt: Double)
case ungueltigerBetrag
case unbekanntesKonto(String)
var description: String {
switch self {
case .zuWenigGuthaben(let f): return "Guthaben reicht nicht, es fehlen \(f)"
case .ungueltigerBetrag: return "ungültiger Betrag"
case .unbekanntesKonto(let n): return "Konto \(n) unbekannt"
}
}
}
final class Bank {
private var konten: [String: Double] = [:]
func eroeffne(_ name: String, start: Double = 0) { konten[name] = start }
func stand(_ name: String) throws -> Double {
guard let s = konten[name] else { throw BankFehler.unbekanntesKonto(name) }
return s
}
func ueberweise(von: String, an: String, betrag: Double) throws {
guard betrag > 0 else { throw BankFehler.ungueltigerBetrag }
let vonStand = try stand(von)
_ = try stand(an)
guard vonStand >= betrag else { throw BankFehler.zuWenigGuthaben(fehlt: betrag - vonStand) }
konten[von]! -= betrag
konten[an]! += betrag
}
}
let bank = Bank()
bank.eroeffne("Mia", start: 100)
bank.eroeffne("Tom")
let versuche: [(String, String, Double)] = [("Mia", "Tom", 30), ("Tom", "Mia", 50), ("Mia", "Ben", 5), ("Mia", "Tom", -1)]
for (von, an, betrag) in versuche {
do {
try bank.ueberweise(von: von, an: an, betrag: betrag)
print("OK: \(von) -> \(an): \(betrag)")
} catch {
print("Fehler: \(error)")
}
}
print(try bank.stand("Mia"), try bank.stand("Tom"))Ausgabe:
OK: Mia -> Tom: 30.0
Fehler: Guthaben reicht nicht, es fehlen 20.0
Fehler: Konto Ben unbekannt
Fehler: ungültiger Betrag
70.0 30.0Projekt 3: Rekursion und Algorithmen
func fib(_ n: Int, _ memo: inout [Int: Int]) -> Int {
if n < 2 { return n }
if let v = memo[n] { return v }
let ergebnis = fib(n - 1, &memo) + fib(n - 2, &memo)
memo[n] = ergebnis
return ergebnis
}
func primzahlen(bis n: Int) -> [Int] {
var sieb = Array(repeating: true, count: n + 1)
sieb[0] = false; if n >= 1 { sieb[1] = false }
var i = 2
while i * i <= n {
if sieb[i] { for j in stride(from: i * i, through: n, by: i) { sieb[j] = false } }
i += 1
}
return sieb.enumerated().filter { $0.element }.map { $0.offset }
}
func binaereSuche<T: Comparable>(_ liste: [T], _ ziel: T) -> Int? {
var lo = 0, hi = liste.count - 1
while lo <= hi {
let mitte = (lo + hi) / 2
if liste[mitte] == ziel { return mitte }
if liste[mitte] < ziel { lo = mitte + 1 } else { hi = mitte - 1 }
}
return nil
}
func istPalindrom(_ s: String) -> Bool {
let sauber = s.lowercased().filter { $0.isLetter }
return sauber == String(sauber.reversed())
}
var memo: [Int: Int] = [:]
print(fib(60, &memo))
print(primzahlen(bis: 50))
print(binaereSuche([1, 3, 5, 7, 9, 11], 7) as Any, binaereSuche([1, 3, 5], 4) as Any)
print(istPalindrom("A man, a plan, a canal: Panama"), istPalindrom("Swift"))
print((1...5).reduce(1, *), (1...100).filter { $0 % 7 == 0 }.count)Ausgabe:
1548008755920
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
Optional(3) nil
true false
120 14Merke
- Mit
Dictionary,map/filter/reduceund Sortierung entstehen Auswertungen in wenigen Zeilen - Eigene Fehlertypen mit
CustomStringConvertiblemachen Fehlermeldungen lesbar - Rekursion mit Memoization, Sieb des Eratosthenes, binäre Suche sind klassische Übungen
- Klassen eignen sich für gemeinsamen veränderlichen Zustand (hier
Bank)
Übungsaufgabe
Erweitere die Bank um eine Methode zinsen(prozent:), die alle Konten verzinst.
Quiz zur Selbstkontrolle
Wann bietet sich eine class statt eines struct an?
- Wenn mehrere Stellen dasselbe veränderliche Objekt teilen sollen (richtig)
- Immer
- Nie
- Für Zahlen
Wofür ist ein eigener Fehlertyp (enum: Error) gut?
- Fehlerfälle benennen und gezielt behandeln (richtig)
- Schnellerer Code
- Weniger Speicher
- Weil Swift es verlangt
Was ist Memoization?
- Berechnete Ergebnisse zwischenspeichern (richtig)
- Texte merken
- Variablen löschen
- Threads starten
Weiter im Kurs
Zurück: Nebenläufigkeit, SwiftUI und Ökosystem
Weiter: Referenz und Spickzettel
Alle Kapitel: Swift im Überblick