2009-06-21 28 views
10

Ich lerne Scala und erkunde einige funktionale Aspekte der Sprache.Aggregierte Listenwerte in Scala

Beginnend mit einer Liste von Objekten, die zwei Parameter fiktive und Währung enthalten, wie kann ich den Gesamtnennwert pro Währung zusammenfassen?

//sample data 
val t1 = new Trade("T150310", 10000000, "GBP"); 
val t2 = new Trade("T150311", 10000000, "JPY"); 
val t3 = new Trade("T150312", 10000000, "USD"); 
val t4 = new Trade("T150313", 100, "JPY"); 
val t5 = new Trade("T150314", 1000, "GBP"); 
val t6 = new Trade("T150315", 10000, "USD"); 

val trades = List(t1, t2, t3, t4, t5, t6); 

Antwort

4

Ich schrieb eine einfache Gruppe-by-Betrieb (eigentlich ein Groupabletrait mit einer impliziten Umwandlung von einem Iterable), die Sie zu einer Gruppe durch ihre currency erlauben würde, Ihre Geschäfte:

trait Groupable[V] extends Iterable[V] { 
    def groupBy(f: V => K): MultiMap[K, V] = { 
    val m = new mutable.HashMap[K, Set[V]] with mutable.MultiMap[K, V] 
    foreach { v => m add (f(v), v) } //add is defined in MultiMap 
    m 
    } 
} 
implicit def it2groupable(it: Iterable[V]): Groupable[V] = new Groupable[V] { 
    def elements = it.elements 
} 

So Groupable ist Sie können einfach einen Schlüssel aus jedem Element in einem Iterable extrahieren und dann alle solche Elemente gruppieren, die den gleichen Schlüssel haben. Also, in Ihrem Fall:

//mm is a MultiMap[Currency, Trade] 
val mm = trades groupBy { _.currency } 

können Sie tun jetzt eine ganz einfache mapElements (mm ist ein Map) und eine foldLeft (oder /: - lohnt sich das Verständnis der foldLeft Betreiber, da es extrem kurze Aggregationen über Sammlungen ermöglicht) zu Holen Sie sich die Summe:

val sums: Map[Currency, Int] = mm mapElements { ts => 
    (0 /: ts) { (sum,t) => sum + t.notional } 
} 

Entschuldigung, wenn ich in dieser letzten Zeile einige Fehler gemacht habe. ts sind die Werte von mm, die (natürlich) Iterable[Trade] sind.

+0

Entschuldigung, aus irgendeinem Grund las ich "Trade" aber hörte "Tuple" in meiner ursprünglichen Antwort. Ich habe es jetzt bearbeitet! –

16

Wenn Sie Kofferraum verwenden, ist die Maschine schon da. groupBy ist auf Traversable definiert und die Summe kann direkt auf die Liste angewendet werden, Sie müssen keine Faltung schreiben.

scala> trades groupBy (_.currency) map { case (k,v) => k -> (v map (_.amount) sum) } 
res1: Iterable[(String, Int)] = List((GBP,10001000), (JPY,10000100), (USD,10010000)) 
+0

Kommt das in 2.8? –

+0

Und können Sie erklären, woher die Summenfunktion kommt? –

+0

Ja, was Stamm ist jetzt, was 2.8 sein wird. Die Summenmethode ist auf NumericTraversableOps definiert - was keine Klasse ist, über die Sie etwas wissen müssen -, aber sie fügt Methoden zu Traversable implizit basierend auf dem Vorhandensein einer Numeric [T] hinzu, die selbst "add" so sum definiert kann generisch definiert werden. – extempore