例如,假设我希望读取脂肪、碳水化合物和蛋白质,并希望打印每个变量的运行总数。命令式样式如下所示:
var totalFat = 0.0
var totalCarbs = 0.0
var totalProtein = 0.0
var lineNumber = 0
for (lineData <- allData) {
totalFat += lineData...
totalCarbs += lineData...
totalProtein += lineData...
lineNumber += 1
printCSV(lineNumber, totalFat, totalCarbs, totalProtein)
}
我如何只用值来写上面的代码?
使用scanLeft
val zs = allData.scanLeft((0, 0.0, 0.0, 0.0)) { case(r, c) =>
val lineNr = r._1 + 1
val fat = r._2 + c...
val carbs = r._3 + c...
val protein = r._4 + c...
(lineNr, fat, carbs, protein)
}
zs foreach Function.tupled(printCSV)
递归。将前一行的总和传递给一个函数,该函数将它们与当前行的值相加,将它们打印到CSV并传递给自身…
您可以使用map
转换数据并使用sum
获得总结果:
val total = allData map { ... } sum
对于scanLeft
,您可以得到每一步的特定和:
val steps = allData.scanLeft(0) { case (sum,lineData) => sum+lineData}
val result = steps.last
如果你想在一个迭代步骤中创建几个新值,我更喜欢一个保存值的类:
case class X(i: Int, str: String)
object X {
def empty = X(0, "")
}
(1 to 10).scanLeft(X.empty) { case (sum, data) => X(sum.i+data, sum.str+data) }
就是向左跳转,
然后向右折叠/:
class Data (val a: Int, val b: Int, val c: Int)
val list = List (new Data (3, 4, 5), new Data (4, 2, 3),
new Data (0, 6, 2), new Data (2, 4, 8))
val res = (new Data (0, 0, 0) /: list)
((acc, x) => new Data (acc.a + x.a, acc.b + x.b, acc.c + x.c))