Mehr Collection-Origami


Nachdem ich mit meinem Mappen-und-Falten-Artikel nicht nur viele Anhänger der japanischen Faltkunst enttäuscht, sondern auch die grundlegenden Operationen forEach, map, flatMap, reduceLeft/Right und foldLeftRight behandelt habe, will ich hier weitere nützliche Operationen vorstellen. Wie ihr sicher schon gehört habt, wurde die Collection-Bibliothek für Scala 2.8 völlig überarbeitet, weshalb einige Beispiele auf 2.7 nicht laufen werden. Ich möchte mich hier erst einmal auf Methoden von Traversable, einem der grundlegendsten Collection-Typen, beschränken.

splitAt, partition, span

Diese drei Operationen teilen das Traversable jeweils in zwei Teile, die Rückgabewerte sind jeweils Tupel, die diese Teile enthalten. splitAt teilt die Collection am vorgegeben Index, und partition und span anhand einer Bedingung. Der Unterschied zwischen partition und span ist, dass partition je nach Ergebnis „true“ oder „false“ die Elemente in den ersten oder zweiten Teil packt, während span nur die Werte bis zum ersten „false“ (exklusive) in den ersten Teil packt, alle weiteren Elemente landen unabhängig von der Auswertung im zweiten Teil.

val list=List(1,2,3,4,5,6,7,8)

println(list.splitAt(3))
//--> (List(1, 2, 3),List(4, 5, 6, 7, 8))

println(list.partition(_ % 3 == 2))
//--> (List(2, 5, 8),List(1, 3, 4, 6, 7))

println(list.span(_ != 6))
//-->(List(1, 2, 3, 4, 5),List(6, 7, 8))

groupBy

Ein sehr nützliche Methode ist groupBy, die die Elemente in eine Map packt, wobei sich die Schlüssel aus einer mitgelieferten Funktion berechnen.

val liste=List(1,2,3,4,5,6,7,8)
println(liste.groupBy(_ % 3))
//--> Map(1 -> List(1, 4, 7), 2 -> List(2, 5, 8), 0 -> List(3, 6))

val list = List("wenn","ich","du","wäre","wäre","ich","lieber","ich")
println(list.groupBy(_(0)))
//--> Map(w -> List(wenn, wäre, wäre), i -> List(ich, ich, ich), d -> List(du), l -> List(lieber))
println(list.groupBy(_.length))
//--> Map(4 -> List(wenn, wäre, wäre), 3 -> List(ich, ich, ich), 2 -> List(du), 6 -> List(lieber))
println(list.groupBy(identity))
//--> Map(lieber -> List(lieber), wenn -> List(wenn), ich -> List(ich, ich, ich), du -> List(du), wäre -> List(wäre, wäre))
println(list.groupBy(identity).map(t => (t._1,t._2.length)))
//--> Map(lieber -> 1, wenn -> 1, ich -> 3, du -> 1, wäre -> 2)

Die letzten beiden Zeilen zeigen, wie man groupBy benutzen kann, um damit die Häufigkeit eines Elements zu zählen.

partialMap

Eine partielle Funktion ist eine Funktin, die nicht überall definiert ist. Typische Beispiele wären Maps (in denen ja meist nicht alle Schlüssel des Definitionsbereichs gespeichert sind) oder match-Ausdrücke. partialMap arbeitet ähnlich wie die map-Methode, nur dass sie „fehlende“ Werte einfach weglässt, statt einen Fehler zu melden. Hier wird jedes Wort, das mit d anfängt, durch 1 ersetzt, und jedes, das mit i anfängt, durch 2:

val list = List("wenn","ich","du","wäre","wäre","ich","lieber","ich")
println(list.partialMap(_(0) match { case 'd' => 1; case 'i' => 2 }))
//--> List(2, 1, 2, 2)

//Mit map funktioniert es nicht:
println(list.map(_(0) match { case 'd' => 1; case 'i' => 2 }))
//--> Exception in thread "main" scala.MatchError: w

reduceLeftOption, reduceRightOption

Die Methoden reduceLeft und reduceRight sind recht praktisch (und einfacher zu verstehen als foldLeft und foldRight). Ihr größtes Manko ist allerdings, dass die Collection nicht leer sein darf. Deshalb verpacken die reduceLeft/RightOption Methoden das Ergebnis in eine Option und liefern bei leeren Collections einfach None.

val list = List("wenn","ich","du","wäre","wäre","ich","lieber","ich")
println(list.reduceLeftOption(_ + _))
//--> Some(wennichduwärewäreichlieberich)
println(list.reduceLeft(_ + _))
//--> wennichduwärewäreichlieberich

val list1 = List[String]()
println(list1.reduceLeftOption(_ + _))
//--> None
println(list1.reduceLeft(_ + _))
//--> Exception in thread "main" java.lang.UnsupportedOperationException: empty.reduceLeft

Ich hoffe, euch hat diese kleine Tour gefallen. Es war ein wenig mühselig, in den Scala-Sourcen nach solchen nützlichen Methoden zu buddeln, hoffentlich gibt es bald eine ordentliche Übersicht für die neuen Scala-Collections. Aber das, was ich dort sehe, halte ich für einen bemerkenswerten Fortschritt gegenüber den alten Collections.

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s