2009-06-21 9 views
10

Sto imparando Scala ed esplorando alcuni degli aspetti funzionali della lingua.Valori di elenco aggregati in Scala

A partire da un elenco di oggetti contenenti due parametri nozionali e valuta, come è possibile aggregare il totale nozionale per valuta?

//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); 

risposta

4

ho scritto un semplice gruppo-by (in realtà un Groupabletrait con una conversione implicita da un Iterable) che consentirebbe di raggruppare i vostri commerci con la loro currency:

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 
} 

Così Groupable è semplicemente fornendo un modo per estrarre una chiave da ogni articolo in un Iterable e quindi raggruppare tutti gli elementi che hanno la stessa chiave. Quindi, nel tuo caso:

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

È ora possibile fare un po semplice mapElements (mm è un Map) e una foldLeft (o /: - vale la pena comprendere l'operatore foldLeft in quanto consente aggregazioni estremamente concise sugli incassi) per Ottenere la somma:

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

Mi scuso se ho fatto alcuni errori in quest'ultima riga. ts sono i valori di mm, che sono (ovviamente) Iterable[Trade].

+0

Mi dispiace, per qualche motivo ho letto "Trade" ma ho sentito "Tuple" nella mia risposta originale. L'ho modificato ora! –

16

Se si utilizza il bagagliaio, la macchina è già presente. groupBy è definito su Traversable e la somma può essere applicata direttamente all'elenco, non è necessario scrivere una piega.

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

Arriva in 2,8? –

+0

E puoi spiegare da dove viene la funzione somma? –

+0

Sì, ciò che è ora tronco è ciò che sarà 2.8. Il metodo sum è definito su NumericTraversableOps - che non è una classe di cui devi sapere nulla - ma fondamentalmente aggiunge metodi a Traversable in modo implicito basato sulla presenza di un Numeric [T], che a sua volta definisce "add" così somma può essere definito genericamente – extempore