下面的示例是我从较大的应用程序中提取的一个独立的示例。
在调用下面的mapValues之后,是否有更好的方法来获取HashMap?我是Scala的新手,所以很可能我要解决所有这些错误,在这种情况下,可以随意提出一种完全不同的方法。 (一个显而易见的解决方案是将mapValues
中的逻辑移到accum
内部,但这在较大的应用程序中会很棘手。)
#!/bin/sh
exec scala "$0" "$@"
!#
import scala.collection.immutable.HashMap
case class Quantity(val name: String, val amount: Double)
class PercentsUsage {
type PercentsOfTotal = HashMap[String, Double]
var quantities = List[Quantity]()
def total: Double = (quantities map { t => t.amount }).sum
def addQuantity(qty: Quantity) = {
quantities = qty :: quantities
}
def percentages: PercentsOfTotal = {
def accum(m: PercentsOfTotal, qty: Quantity) = {
m + (qty.name -> (qty.amount + (m getOrElse (qty.name, 0.0))))
}
val emptyMap = new PercentsOfTotal()
// The `emptyMap ++` at the beginning feels clumsy, but it does the
// job of giving me a PercentsOfTotal as the result of the method.
emptyMap ++ (quantities.foldLeft(emptyMap)(accum(_, _)) mapValues (dollars => dollars / total))
}
}
val pu = new PercentsUsage()
pu.addQuantity(new Quantity("A", 100))
pu.addQuantity(new Quantity("B", 400))
val pot = pu.percentages
println(pot("A")) // prints 0.2
println(pot("B")) // prints 0.8
最佳答案
除了使用可变的HashMap
来构建自己的Map
之外,您还可以使用内置于 groupBy
函数的scala集合。这会创建一个从分组属性到该组中值列表的映射,然后可以将其汇总,例如通过求和:
def percentages: Map[String, Double] = {
val t = total
quantities.groupBy(_.name).mapValues(_.map(_.amount).sum / t)
}
该管道可以转换
List[Quantity]
=> Map[String, List[Quantity]]
=> Map[String, Double]
,从而为您提供所需的结果。