Scala - 总结列表中的每个成员?

时间:2017-02-26 20:40:36

标签: scala

如果我有一个对象列表(所有相同类型),我可以从中获得某种类型的地图,其中地图中的每个条目对应于该类型的成员(无论这是由我设置还是由system是无关紧要的)并且每个条目的值是列表中所有成员值的总和?

例如,给定一个具有成员薪水,小时和身高的对象,以及其中几个对象的列表,是否有一些scala代码可以让我回到一个带有" height"作为高峰的总和,"薪水"作为工资和"小时"的总和作为小时数的总和?

抱歉,我对Scala完全不熟悉 - 我只是想尝试使用Twirl在playframework中工作。

2 个答案:

答案 0 :(得分:1)

这是一种方法。

我们将创建一个案例类Item来表示具有高度,小时和工资成员的类,以及它们的列表:

case class Item(val height: Int, val hours: Int, val salary: Double)
val items = List(Item(3, 4, 10.0), Item(9, 100, 123.0))

然后只需初始化一个3元组并使用foldLeft来累积每个成员的总和。

val sums = items.foldLeft((0, 0, 0.0))((x, item) => 
    (x._1 + item.height, x._2 + item.hours, x._3 + item.salary))

我们可以将值累积到Item的另一个实例中,或者累积到具有三个成员的Map中。这没关系。原理是相同的:初始化一个对象以保存总和,然后foldLeft在集合上。

使用元组(而不是您请求的映射)的好处是您可以将每个元组成员分配给一个单独的变量:

val (sumHeight, sumHurs, sumSalary) = items.foldLeft((0, 0, 0.0))((x, item) => 
    (x._1 + item.height, x._2 + item.hours, x._3 + item.salary))

答案 1 :(得分:0)

我的解决方案略有不同。 如果您只想对所有项目求和,Scala集合已经提供了一个'sum'函数来汇总项目。 但是,为了能够使用它,您需要为案例类使用Numeric实现。

因此对于案例类Item:

case class Item(salary: Double, hours: Int, height: Int)

可以在Item的伴随对象中定义隐式Numeric [Item]实例:

object Item {
  implicit object NumericItem extends Numeric[Item] {
    override def plus(x: Item, y: Item): Item = Item(
      salary = x.salary + y.salary,
      hours  = x.hours  + y.hours,
      height = x.height + y.height
    )

    override def minus(x: Item, y: Item): Item = ???

    override def times(x: Item, y: Item): Item = ???

    override def negate(x: Item): Item = ???

    // Needed to provide starting point for folding using 'sum'
    override def fromInt(x: Int): Item = {
      Item(0,0,0)
    }

    override def toInt(x: Item): Int = ???

    override def toLong(x: Item): Long = ???

    override def toFloat(x: Item): Float = ???

    override def toDouble(x: Item): Double = ???

    override def compare(x: Item, y: Item): Int = ???
  }
}

为了支持'sum'功能,只需要实现Numeric的'plus'和'fromInt'功能。

现在列表中的所有项目

val items = List(Item(10.0, 1, 5), Item(5.0, 2, 3), Item(2.5, 3, 8))
items: List[Item] = List(Item(10.0,1,5), Item(5.0,2,3), Item(2.5,3,8))

可以使用'sum'

求和
val total = items.sum
total: Item = Item(17.5,6,16)

现在总数可以用作'total.salary'等,但是如果你想要一张地图,可以在Item中提供一个简单的'toMap'功能

  def toMap: Map[String, Any] = Map(
    "salary" -> salary,
    "hours"  -> hours,
    "height" -> height
  )

总计地图可以通过

获得
totals.toMap
res0: Map[String,Any] = Map(salary -> 17.5, hours -> 6, height -> 16)