Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Scala, how do I keep track of running totals without using var?

Tags:

scala

For example, suppose I wish to read in fat, carbs and protein and wish to print the running total of each variable. An imperative style would look like the following:

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)

}

How would I write the above using only vals?

like image 327
deltanovember Avatar asked Jul 23 '11 09:07

deltanovember


3 Answers

Use 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)
like image 144
missingfaktor Avatar answered Oct 22 '22 07:10

missingfaktor


Recursion. Pass the sums from previous row to a function that will add them to values from current row, print them to CSV and pass them to itself...

like image 27
Mchl Avatar answered Oct 22 '22 08:10

Mchl


You can transform your data with map and get the total result with sum:

val total = allData map { ... } sum

With scanLeft you get the particular sums of each step:

val steps = allData.scanLeft(0) { case (sum,lineData) => sum+lineData}
val result = steps.last

If you want to create several new values in one iteration step I would prefer a class which hold the values:

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) }
like image 2
kiritsuku Avatar answered Oct 22 '22 09:10

kiritsuku