EMZETT.
Login

Kurz: let text = """ Swift ist schnell. Swift ist sicher, und Swift macht Spaß! Sicher und schnell: das ist Swift. """

Teil des Kurses Swift

Kapitel 7 von 8 im Kurs Swift (Abschnitt „Projekte“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

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: schnell

Projekt 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.0

Projekt 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 14

Merke

  • Mit Dictionary, map/filter/reduce und Sortierung entstehen Auswertungen in wenigen Zeilen
  • Eigene Fehlertypen mit CustomStringConvertible machen 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

Weiter im Kurs

Zurück: Nebenläufigkeit, SwiftUI und Ökosystem

Weiter: Referenz und Spickzettel

Alle Kapitel: Swift im Überblick