Совокупные значения в Scala

Я изучаю Scala и изучаю некоторые функциональные аспекты языка.

Начиная со списка объектов, содержащих два условных значения и валюту, как я могу суммировать общую условную валюту?

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

Ответ 1

Я написал простую групповую операцию (на самом деле a Groupable trait с неявным преобразованием из Iterable), что позволило бы группировать ваши сделки с помощью 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
}

Итак, Groupable просто предоставляет способ извлечь ключ из каждого элемента в Iterable и затем группировать все такие элементы, которые имеют один и тот же ключ. Итак, в вашем случае:

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

Теперь вы можете сделать довольно простой mapElements (mm - это Map) и foldLeft (или /:), хорошо понимающий оператор foldLeft, поскольку он обеспечивает чрезвычайно сжатые скопления над наборами), чтобы получить сумму:

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

Извините, если я допустил некоторые ошибки в этой последней строке. ts - значения mm, которые (конечно) Iterable[Trade].

Ответ 2

Если вы используете багажник, оборудование уже существует. groupBy определяется на Traversable, и сумма может быть применена непосредственно к списку, вам не нужно писать сгиб.

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