CSV-Daten
Ein schönes Einsteigerprojekt ist die Verarbeitung von CSV-Dateien mit Temperaturdaten. Dabei kannst du funktionale Werkzeuge wie map
, filter
, reduce
und ->>
verwenden.
Ziel: Fahrenheit in Celsius umrechnen und Durchschnitt berechnen
Beispielinhalt einer Datei temps.csv
:
|
|
Der Code soll die Temperaturen in °C umrechnen und einen Mittelwert ausgeben. Die Formel für die Umrechnung von Fahrenheit ist:
$$T_\mathrm{Celsius} = \frac{5}{9} \left( T_\mathrm{Fahrenheit} - 32 \right)$$Lösung
Abhängigkeit für CSV eintragen
In project.clj
unter :dependencies
:
|
|
Dann:
|
|
CSV lesen und verarbeiten
|
|
with-open
öffnet die Datei sicher und schließt sie automatisch nach dem Lesen.csv/read-csv
liest die Datei zeilenweise und parst jede Zeile als Vektor von Strings.rest
überspringt die erste Zeile (Header).map #(Double/parseDouble (second %)) rows
extrahiert den zweiten Spaltenwert (Temperatur) und wandelt ihn in eine Zahl um.map fahr->celsius
konvertiert alle Fahrenheit-Werte in Celsius (Teil der->>
-Kette).avg
berechnet den Mittelwert der umgerechneten Celsius-Werte (ebenfalls in der->>
-Kette).- Das Ergebnis wird mit
println
ausgegeben.
Testaufruf in -main
|
|
Die Datei
temps.csv
legst du unterresources/
ab.
Dann:
|
|
Erwartete Ausgabe:
Durchschnitt: 26,7 °C
Du kannst auf diese Weise viele funktionale Konzepte trainieren: Mapping, Reduktion, Transformation und I/O.
Exkurs: Threading-Makros
Der ->>
Operator ist eines der bekanntesten Makros in Clojure und gehört zur Familie der sogenannten Threading-Makros. Er wird verwendet, um verschachtelte Funktionsaufrufe übersichtlich zu schreiben – indem das Ergebnis jeweils als letztes Argument in den nächsten Ausdruck eingefügt wird.
Ohne -»
|
|
Mit -»
|
|
->
führt als erstes Argument ein (Thread-First)->>
führt als letztes Argument ein (Thread-Last)
Wofür das gut ist
- Lesbarkeit: Datenfluss wird von oben nach unten sichtbar
- Vermeidet Klammerhölle
- Ideal für Pipelines wie in
map
,filter
,reduce
,avg
Clojure bietet mehrere sogenannte Threading-Makros, um verschachtelte Ausdrücke übersichtlicher zu schreiben:
Makro | Beschreibung | Beispiel |
---|---|---|
-> | Thread-First: Ergebnis wird als erstes Argument eingesetzt | (-> x (f a) (g b)) ⇒ (g (f x a) b) |
->> | Thread-Last: Ergebnis wird als letztes Argument eingesetzt | (->> x (f a) (g b)) ⇒ (g b (f a x)) |
as-> | Bindet den Zwischenwert an einen Namen (meist <> ) | (as-> x <> (f <>) (g 1 <> 2)) |
some-> | Thread-First, aber nur wenn nicht nil | (some-> user :address :zip) ⇒ nil-safe Zugriff |
Wann was verwenden?
->
ist ideal für Daten, die am Anfang übergeben werden (z. B. bei Maps:(-> user :address :zip)
)->>
ist ideal für Daten, die durch Pipelines laufen (z. B.map
,filter
,reduce
)as->
ist gut, wenn du nicht nur vorne oder hinten einsetzen willstsome->
ist perfekt für optional verkettete Zugriffe mitnil
-Sicherheit