Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional way to map over a list with an accumulator in Scala

I would like to write succinct code to map over a list, accumulating a value as I go and using that value in the output list.

Using a recursive function and pattern matching this is straightforward (see below). But I was wondering if there is a way to do this using the function programming family of combinators like map and fold etc. Obviously map and fold are no good unless you use a mutable variable defined outside the call and modify that in the body.

Perhaps I could do this with a State Monad but was wondering if there is a way to do it that I'm missing, and that utilizes the Scala standard library.

// accumulate(List(10, 20, 20, 30, 20))
// => List(10, 30, 50, 80, 100,)

def accumulate(weights : List[Int], sum : Int = 0, acc: List[Int] = List.empty) : List[Int] = {
  weights match {
    case hd :: tl =>
      val total = hd + sum
      accumulate(tl, total, total :: acc)
    case Nil =>
      acc.reverse
  }
}
like image 854
justinhj Avatar asked Dec 02 '22 11:12

justinhj


2 Answers

This could be done with scan:

val result = list.scanLeft(0){case (acc, item) => acc+item}

Scan will include the initial value 0 into output so you have to drop it:

result.drop(1)
like image 121
Nyavro Avatar answered Dec 05 '22 06:12

Nyavro


You may also use foldLeft:

def accumulate(seq: Seq[Int]) =
  seq.foldLeft(Vector.empty[Int]) { (result, e) =>
    result :+ result.lastOption.getOrElse(0) + e
  }

accumulate(List(10, 20, 20, 30, 20))
// => List(10, 30, 50, 80, 100,)
like image 38
PH88 Avatar answered Dec 05 '22 04:12

PH88