scala: avoid a var while iterating and accumulating in a functional manner (no vars)

Viewed 44

I need help to find the right Scala approach that will make this code more functional and less mutable.

  def findMinTime(str: String, timeByCar: Int): Int = {
    var myTime = timeByCar
    var minTime = timeByCar
    str.reverse.foreach { l =>
      if (l == 'A') myTime += 3 else myTime -= 2
      if (myTime < minTime) minTime = myTime
    }
    minTime
  }
2 Answers

foldLeft is one way, useful when logic is simple and concise. But in general the go-to tool for this kind of tasks in scala is (tail) recursion:

`

def findMinTime(str: String, timeByCar: Int) = {
  @tailrec
  def loop(str: List[Char], minTime: Int, myTime: Int): Int = str match {
     case Nil => minTime
     case 'A' :: tail => loop(tail, myTime+3, minTime min myTime+3)
     case _ :: tail => loop(tail, myTime -2, minTime min myTime-2)
  }
  loop(str.toList.reverse, timeByCar, timeByCar)
}

Here's a solution using foldLeft. We store the two variables we need to modify after each character (myTime and minTime) in a tuple as the accumulator.

def findMinTime(str: String, timeByCar: Int): Int = {
  val (myTime, minTime) = str.reverse.foldLeft((timeByCar, timeByCar)) {
    case ((myTime, minTime), l) =>
      val newTime = if (l == 'A') myTime + 3 else myTime - 2
      (newTime, newTime min minTime)
  }
  minTime
}
Related