Collections: Überblick und Hintergründe
Die Collections-Bibliothek ist das Werkzeug, das Sie in Scala am häufigsten benutzen werden. Sie ist einheitlich aufgebaut: Wer die Methoden einer Sammlung kennt, kann fast alle anderen sofort bedienen. Diese Seite ordnet die Typen ein und hilft bei der Auswahl.
Der Aufbau
Ganz oben steht Iterable: alles, was sich der Reihe nach durchlaufen lässt. Darunter gibt es drei große Familien:
- Seq – Folgen mit fester Reihenfolge und Index:
List,Vector,ArrayBuffer, auchRangeundString. - Set – Mengen ohne Duplikate:
HashSet,TreeSet. - Map – Zuordnungen von Schlüsseln zu Werten:
HashMap,TreeMap,VectorMap.
Jede Familie gibt es in zwei Varianten: in scala.collection.immutable (unveränderlich, der Standard) und in scala.collection.mutable (veränderlich). Schreiben Sie einfach List, Set oder Map, erhalten Sie die unveränderliche Variante.
Unveränderlich als Standard
Unveränderliche Collections werden nie verändert. Methoden wie :+, updated oder filter liefern eine neue Sammlung. Das klingt teuer, ist es aber meist nicht: Die neue und die alte Sammlung teilen sich intern den größten Teil ihrer Struktur. Dafür dürfen Sie unveränderliche Collections ohne Vorsicht zwischen Funktionen und Threads weitergeben.
Auswahlhilfe
| Sie brauchen … | nehmen Sie |
|---|---|
| eine Folge, die vorne wächst und rekursiv zerlegt wird | List |
| eine Folge mit Indexzugriff oder Anhängen am Ende | Vector |
| eine wachsende Folge in einer lokalen Schleife | ArrayBuffer oder ListBuffer |
| schnelle Prüfung „enthalten?“, keine Duplikate | Set |
| sortierte Menge | SortedSet (TreeSet) |
| Zuordnung Schlüssel → Wert | Map |
| Zuordnung mit Einfügereihenfolge | VectorMap |
| Zahlenfolge ohne Speicherbedarf | Range (1 to 100) |
| Java-Array-Schnittstelle, primitive Zahlen | Array |
Im Zweifel ist Vector die sicherste Wahl für allgemeine Folgen: überall schnell, nirgends dramatisch langsam. List spielt ihre Stärke aus, wenn Sie mit Kopf und Rest arbeiten.
Eine Methode, alle Collections
Die meisten Methoden stehen auf allen Collections zur Verfügung und liefern – wo sinnvoll – denselben Typ zurück:
List(1, 2, 3).map(_ * 2) // List(2, 4, 6)
Vector(1, 2, 3).map(_ * 2) // Vector(2, 4, 6)
Set(1, 2, 3).map(_ % 2) // Set(1, 0)
Map("a" -> 1).map((k, v) => k -> v * 10) // Map(a -> 10)
"abc".map(_.toUpper) // "ABC"Wichtige Gruppen von Methoden:
- Umwandeln:
map,flatMap,collect - Auswählen:
filter,filterNot,take,drop,takeWhile,slice - Prüfen:
exists,forall,contains,isEmpty - Suchen:
find,indexOf,headOption,lastOption - Zusammenfassen:
foldLeft,reduce,sum,max,count,mkString - Ordnen:
sorted,sortBy,sortWith,reverse - Gruppieren:
groupBy,groupMapReduce,partition,grouped,sliding - Kombinieren:
zip,++,concat,diff,intersect - Umwandeln in andere Typen:
toList,toVector,toSet,toMap,to(…)
Views und LazyList
Ketten wie xs.map(f).filter(p).take(10) erzeugen bei jedem Schritt eine Zwischensammlung. Mit .view werden die Schritte stattdessen erst ausgeführt, wenn das Ergebnis gebraucht wird – und nur für so viele Elemente wie nötig:
(1 to 1_000_000).view.map(n => n * n).filter(_ % 7 == 0).take(3).toList
// List(49, 196, 441) – ohne eine Million ZwischenwerteLazyList geht noch weiter und kann sogar unendlich sein:
val fib: LazyList[BigInt] = BigInt(0) #:: BigInt(1) #:: fib.zip(fib.tail).map(_ + _)
fib.take(10).toList // List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)Stufe 5: Collections
List, Set, Map, Vector und die veränderlichen Verwandten – mit den wichtigsten Methoden.
- 25List und ihre FunktionenDie unveränderliche Liste und ihre wichtigsten Methoden.
- 26Set: Mengen ohne DuplikateMengen, Enthaltensein, Vereinigung und Schnitt.
- 27Map: Schlüssel und WerteSchlüssel-Wert-Paare, sicherer Zugriff und Auswertungen.
- 28Array und veränderliche CollectionsArray, ArrayBuffer, ListBuffer – und wann sie sich lohnen.