繁体   English   中英

在Scala中使用累加器映射列表的功能方法

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

我想编写简洁的代码来映​​射列表,在我去的时候累积一个值并在输出列表中使用该值。

使用递归函数和模式匹配这很简单(见下文)。 但我想知道是否有办法使用组合函数编程系列,如map和fold等。显然map和fold是没有用的,除非你使用在调用之外定义的可变变量并在体内修改它。

也许我可以用状态Monad做到这一点但是想知道是否有一种方法可以做到这一点,我缺少了,并且利用了Scala标准库。

// 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
  }
}

您也可以使用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,)

这可以通过扫描完成:

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

扫描将初始值0包含在输出中,因此您必须删除它:

result.drop(1)

正如在@ Nyavro的回答中指出的那样,您正在寻找的操作(列表前缀的总和 )称为前缀和 ,它对任何二进制操作的泛化称为scan ,并包含在Scala标准库中

val l = List(10, 20, 20, 30, 20)

l.scan(0) { _ + _ }
//=> List(0, 10, 30, 50, 80, 100)

l.scan(0)(_ + _).drop(1)
//=> List(10, 30, 50, 80, 100)

这已经得到了回答,但我想在你的问题中解决一个误解:

显然,除非你使用在调用之外定义的可变变量并在体内修改它,否则map和fold是没有用的。

事实并非如此。 fold是一种通用的迭代方法。 你可以通过遍历集合来做所有事情 ,你可以做fold 如果foldList类中唯一的方法,你仍然可以做你现在可以做的一切。 以下是如何使用fold解决您的问题:

l.foldLeft(List(0)) { (list, el) ⇒ list.head + el :: list }.reverse.drop(1)

并且scan的一般实现:

def scan[A](l: List[A])(z: A)(op: (A, A) ⇒ A) = 
  l.
    drop(1).
    foldLeft(List(l.head)) { (list, el) ⇒ op(list.head, el) :: list }.
    reverse

可以这样想:集合可以是空的也可以不是。 fold有两个参数,一个告诉它在列表为空时该怎么做,另一个告诉它在列表不为空时该怎么做。 这是唯一的两个案例,因此每个可能的案件都得到处理。 因此, fold可以做任何事情! (更准确地说,在Scala中, foldLeftfoldRight可以执行任何操作,而fold仅限于关联操作。)

或者不同的观点:集合是指令流,可以是EMPTY指令,也可以是ELEMENT(value)指令。 foldLeft / foldRight是该指令集的骨架解释器 ,作为程序员,您可以提供对这两个指令的解释的实现,即foldLeft / foldRight的两个参数对这些指令的解释。

请记住:虽然foldLeft / foldRight将集合缩减为单个值,但该值可以是任意复杂的,包括作为集合本身!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM