我有一个班级
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
来分解值,但我不知道如何让它们一起工作。
答案 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)}