如何使用Scala中的对象列表中的对象值创建求和变量?

时间:2017-07-06 22:27:10

标签: scala functional-programming

我有一个班级

class Test(val first: Int, val second: Int, val third: Int)

类测试可能具有除第一,第二和第三之外的其他属性。

我有一个清单:

val list: List[Test] = List(new Test(0,1,2), new Test(1,14,2), new Test(7,15,2))

我如何在这里使用foldLeft将所有第一个,第二个,第三个一起加在一起以最终得到变量:

allFirsts = 8

allSeconds = 30

allThirds = 6

我已经有了这样的事情:

val (totalFirsts, totalSeconds, totalThirds) = list.foldLeft(0, 0, 0){ (sum, l) => (sum._1 + l.first , sum._2 + l.second, sum._3 + l.third) }

它似乎工作正常,但我不喜欢_1,_2和_3的可读性。也许我可以在这里使用case来分解值,但我不知道如何让它们一起工作。

3 个答案:

答案 0 :(得分:1)

您可以定义另一个案例类来保存初始和最终结果,然后您可以使用first, second, third代替_1, _2, _3

case class Test1(val first: Int, val second: Int, val third: Int)

list.foldLeft(Test1(0,0,0))((acc, t) => Test1(acc.first + t.first, acc.second + t.second, acc.third + t.third))
// res0: Test1 = Test1(8,30,6)

答案 1 :(得分:0)

我不会使用它但它有效

  case class Test3(a1: Int, a2: Int, a3: Int)
  case class Test4(a1: Int, a2: Int, a3: Int, a4: Int)

  import scala.reflect._
  def doMagic[T <: Product : ClassTag](data: List[T]): T ={
    val params: Seq[Object] = data.map(_.productIterator.toList.map(_.asInstanceOf[Int]))
      .reduce((buffer, next) => buffer.zip(next).map { case (i, j) => i + j }).map(_.asInstanceOf[Object])
    classTag[T].runtimeClass.getConstructors()(0).newInstance(params:_*).asInstanceOf[T]
  }
  doMagic(List(Test3(1,2,3), Test3(2,3,4), Test3(10,20,30))) // Test3(13,25,37)
  doMagic(List(Test4(1,2,3,5), Test4(2,3,4,0), Test4(10,20,30,100))) // Test4(13,25,37,105)

不要忘记使用reduceOption而不是reduce来处理空列表。这里使用reduce来简化代码

答案 2 :(得分:0)

你是对的,元组索引可能有点笨重。在这种情况下,您可以使用模式匹配。

val (totalFirsts, totalSeconds, totalThirds) =
  list.foldLeft(0, 0, 0){case ((a,b,c), test) =>
    (a+test.first, b+test.second, c+test.third)}

但语法可以进一步简化。如果您的Test类是case class,那么它将有一个可以在模式匹配中使用的提取器。

case class Test(first: Int, second: Int, third: Int)
. . .
val (totalFirsts, totalSeconds, totalThirds) =
  list.foldLeft(0, 0, 0){case ((a,b,c), Test(f,s,t)) => (a+f, b+s, c+t)}