繁体   English   中英

在Scala中汇总列表值

[英]Aggregate list values in Scala

从包含两个参数“名义”和“货币”的对象列表开始,如何汇总每种货币的名义总数?

鉴于:

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")
)

我怎样才能得到:

Map(JPY -> 10000100, USD -> 10010000, GBP -> 10001000)

如果您使用后备箱,则机器已经存在。 groupBy是在Traversable上定义的,并且sum可以直接应用于列表,而不必编写折叠。

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

我写了一个简单的分组操作(实际上是一个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每个项目中提取密钥 ,然后对所有具有相同密钥的此类项目进行分组的Iterable 因此,在您的情况下:

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

现在,您可以执行一个非常简单的mapElementsmm是一个Map )和一个foldLeft (或/: -值得理解foldLeft运算符,因为它可以实现对集合的极其简洁的聚合)来获取总和:

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

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

Scala 2.13开始,大多数集合都提供有groupMapReduce方法,该方法(顾名思义)等效于groupBy (效率更高),后跟mapValues和reduce步骤:

trades.groupMapReduce(_.currency)(_.amount)(_ + _)
// immutable.Map[String,Int] = Map(JPY -> 10000100, USD -> 10010000, GBP -> 10001000)

这个:

  • group基于其货币小号元件(组的MapReduce的一部分)

  • map分组的值map到其值( Map Reduce组的映射部分)

  • reduce的价值观( _ + _通过对它们求和)(减少groupMap的一部分缩小 )。

这是等效的版本,它通过以下列表的一次执行

trades.groupBy(_.currency).mapValues(_.map(_.amount).reduce(_+_))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM