Aggregate list values in Scala

functional-programming, scala, scala-collections

Solution

I wrote a simple group-by operation (actually a `Groupable` `trait` with an implicit conversion from an `Iterable`) which would allow you to group your trades by their `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
}

So `Groupable` is simply providing a way to extract a key from each item in an `Iterable` and then grouping all such items which have the same key. So, in your case:

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

You can now do a quite simple `mapElements` (`mm` is a `Map`) and a `foldLeft` (or `/:` - well worth understanding the `foldLeft` operator as it enables extremely concise aggregations over collections) to get the sum:

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

Apologies if I've made some mistakes in that last line. `ts` are the values of `mm`, which are (of course) `Iterable[Trade]`.

Problem

Starting with a list of objects containing two parameters notional and currency, how can I aggregate the total notional per currency? Given: ``` case class Trade(name: String, amount: Int, currency: String) val trades = List( Trade("T150310", 10000000, "GBP"), Trade("T150311", 10000000, "JPY"), Trade("T150312", 10000000, "USD"), Trade("T150313", 100, "JPY"), Trade("T150314", 1000, "GBP"), Trade("T150315", 10000, "USD") ) ``` How can I get: ``` Map(JPY -> 10000100, USD -> 10010000, GBP -> 10001000) ```

Original source