In Scala, how do I fold a List and return the intermediate results?

前端 未结 8 951
失恋的感觉
失恋的感觉 2020-12-08 07:12

I\'ve got a List of days in the month:

val days = List(31, 28, 31, ...)

I need to return a List with the cumulative sum of days:

         


        
相关标签:
8条回答
  • 2020-12-08 07:33

    For any:

    val s:Seq[Int] = ...
    

    You can use one of those:

    s.tail.scanLeft(s.head)(_ + _)
    s.scanLeft(0)(_ + _).tail
    

    or folds proposed in other answers but... be aware that Landei's solution is tricky and you should avoid it.

    BE AWARE

    s.map { var s = 0; d => {s += d; s}} 
    //works as long `s` is strict collection
    
    val s2:Seq[Int] = s.view //still seen as Seq[Int]
    s2.map { var s = 0; d => {s += d; s}} 
    //makes really weird things! 
    //Each value'll be different whenever you'll access it!
    

    I should warn about this as a comment below Landei's answer but I couldn't :(.

    0 讨论(0)
  • 2020-12-08 07:39

    Fold your list into a new list. On each iteration, append a value which is the sum of the head + the next input. Then reverse the entire thing.

    scala> val daysInMonths = List(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
    daysInMonths: List[Int] = List(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
    
    scala> daysInMonths.foldLeft(Nil: List[Int]) { (acc,next) => 
         | acc.firstOption.map(_+next).getOrElse(next) :: acc    
         | }.reverse                                             
    res1: List[Int] = List(31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365)
    
    0 讨论(0)
  • You can simply perform it:

    daysInMonths.foldLeft((0, List[Int]()))
                         {(acu,i)=>(i+acu._1, i+acu._1 :: acu._2)}._2.reverse
    
    0 讨论(0)
  • 2020-12-08 07:45

    Fold into a list instead of an integer. Use pair (partial list with the accumulated values, accumulator with the last sum) as state in the fold.

    0 讨论(0)
  • 2020-12-08 07:47

    I'm not sure why everybody seems to insist on using some kind of folding, while you basically want to map the values to the cumulated values...

    val daysInMonths = List(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
    
    val cumulated = daysInMonths.map{var s = 0; d => {s += d; s}}
    
    //--> List[Int] = List(31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365)
    
    0 讨论(0)
  • 2020-12-08 07:47

    You can also create a monoid class that concatenates two lists while adding to the second one the last value from the first. No mutables and no folds involved:

    case class CumSum(v: List[Int]) { def +(o: CumSum) = CumSum(v ::: (o.v map (_ + v.last))) }
    defined class CumSum
    
    scala> List(1,2,3,4,5,6) map {v => CumSum(List(v))} reduce (_ + _)
    res27: CumSum = CumSum(List(1, 3, 6, 10, 15, 21))
    
    0 讨论(0)
提交回复
热议问题