代码之家  ›  专栏  ›  技术社区  ›  Masterbuilder

无变量scala的累积和[重复]

  •  0
  • Masterbuilder  · 技术社区  · 6 年前

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

    我需要返回一个包含累计天数的列表:

    val cumDays = List(31, 59, 90)
    

    我考虑过使用fold运算符:

    (0 /: days)(_ + _)
    

    但这将只返回最终结果(365),而我需要中间结果的列表。

    不管怎样,我能优雅地做到这一点吗?

    0 回复  |  直到 14 年前
        1
  •  55
  •   sepp2k    14 年前

    Scala 2.8有以下方法 scanLeft scanRight 就是这样。

    对于2.7,您可以定义自己的 这样地:

    def scanLeft[a,b](xs:Iterable[a])(s:b)(f : (b,a) => b) =
      xs.foldLeft(List(s))( (acc,x) => f(acc(0), x) :: acc).reverse
    

    然后像这样使用:

    scala> scanLeft(List(1,2,3))(0)(_+_)
    res1: List[Int] = List(0, 1, 3, 6)
    
        2
  •  20
  •   Landei    14 年前

    我不知道为什么每个人都坚持使用某种折叠,而你基本上想把值映射到累积值。。。

    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)
    
        3
  •  6
  •   mucar    12 年前

    您只需执行以下操作:

    daysInMonths.foldLeft((0, List[Int]()))
                         {(acu,i)=>(i+acu._1, i+acu._1 :: acu._2)}._2.reverse
    
        4
  •  2
  •   Mau    14 年前

    折叠成列表而不是整数。在折叠中使用pair(带累积值的部分列表,带最后一个和的累加器)作为状态。

        5
  •  1
  •   Synesso    14 年前

    把你的单子折叠成一个新单子。在每次迭代中,追加一个值,该值是head+下一个输入的和。然后把整个事情颠倒过来。

    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)
    
        6
  •  1
  •   dividebyzero    8 年前

    还可以创建一个monoid类,该类连接两个列表,同时将第一个列表的最后一个值添加到第二个列表。不涉及易变和褶皱:

    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))
    
        7
  •  0
  •   user unknown    14 年前

    关于2.7.7的工作:

    def stepSum (sums: List [Int], steps: List [Int]) : List [Int] = steps match { 
         case Nil => sums.reverse.tail                                                  
         case x :: xs => stepSum (sums.head + x :: sums, steps.tail) }
    
    days
    res10: List[Int] = List(31, 28, 31, 30, 31)
    
    stepSum (List (0), days) 
    res11: List[Int] = List(31, 59, 90, 120, 151)
    
        8
  •  0
  •   Scalway    5 年前

    对于任何:

    val s:Seq[Int] = ...
    

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

    或其他答案中提出的折叠,但。。。

    注意

    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!