2009-06-21 62 views
10

我正在学习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); 

回答

4

我写了一个简单的小组,由操作(实际上是一个Groupabletrait与来自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 } 

现在你可以做一个很简单的mapElementsmmMap)和foldLeft(或/: - 值得了解foldLeft运营商,因为它能够非常简洁聚集在集合)到得到的总和:

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

道歉,如果我在最后一行犯了一些错误。 tsmm的值,当然是Iterable[Trade]

+0

对不起,由于某种原因我读了“贸易”,但在我原来的答案中听到“元组”。我现在编辑它! – 2009-06-21 14:06:19

16

如果您使用后备箱,机器已经存在。 groupBy是在Traversable上定义的,sum可以直接应用到列表中,你不必写一个fold。

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

即将在2.8? – 2009-06-22 22:24:44