2009-06-21 71 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