Scala 中的聚合列表值

发布于 2024-07-24 09:14:51 字数 484 浏览 5 评论 0 原文

从包含名义和货币​​两个参数的对象列表开始,如何聚合每种货币的名义总金额?

鉴于:

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)

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

生寂 2024-07-31 09:14:52

我编写了一个简单的分组操作(实际上是一个从 Iterable 进行隐式转换的 Groupable trait),它允许您对交易进行分组按其货币

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 } 

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

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

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

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].

一笑百媚生 2024-07-31 09:14:52

从 Scala 2.13 开始,大多数集合都提供了 groupMapReduce 方法(顾名思义)与 groupBy 等效(更高效),后跟 mapValues 和一个归约步骤:

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

这是:

  • groups 元素基于其货币(groupMapReduce 的组部分)

  • map将分组值映射到其金额(组MapReduce 的映射部分)

  • 减少的值(_ + _ )通过对它们求和(减少 groupMapReduce 的一部分)。

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

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

Starting Scala 2.13, most collections are provided with the groupMapReduce method which is (as its name suggests) an equivalent (more efficient) of a groupBy followed by mapValues and a reduce step:

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

This:

  • groups elements based on their currency (group part of groupMapReduce)

  • maps grouped values to their amount (map part of groupMapReduce)

  • reduces values (_ + _) by summing them (reduce part of groupMapReduce).

This is an equivalent version performed in one pass through the List of:

trades.groupBy(_.currency).mapValues(_.map(_.amount).reduce(_+_))
紫罗兰の梦幻 2024-07-31 09:14:51

如果你使用后备箱,机器已经在那里了。 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))

If you use trunk the machinery is already there. groupBy is defined on Traversable and sum can be applied directly to the list, you don't have to write a 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))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文