scala中是否有等效的python reduce()函数?

时间:2016-09-14 05:12:27

标签: python scala lambda functional-programming reduce

我刚开始学习Scala和函数式编程,我正在尝试将以下内容从Python转换为Scala:

def immutable_iterative_fibonacci(position):

    if (position ==1):
        return [1]

    if (position == 2):
        return [1,1]

    next_series = lambda series, _: series + [series [-1] + series [-2]]
    return reduce(next_series, range(position - 2), [1, 1])

我无法弄清楚Scala中等效的reduce是什么。这就是我现在拥有的。除了最后一行,一切正常。

def immutable_fibonacci(position: Int) : ArrayBuffer[Int] = {

    if (position == 1){
          return ArrayBuffer(1)
     }

     if (position == 2){
         return ArrayBuffer(1,1)
     }

     var next_series = (series: ArrayBuffer[Int]) => series :+ ( series( series.size - 1) + series( series.size -2))

     return reduce(next_series, 2 to position, ArrayBuffer(1,1))
}

1 个答案:

答案 0 :(得分:11)

Python reduce摘要,供参考:

reduce(function, iterable[, initializer])

Traversable的

要查看的好类型是Traversable,是ArrayBuffer的超类型。您可能只想暂时使用该API,因为那里有很多有用的东西。

减少

当省略reduce arg时,相当于Python的initializer是Scala的Traversable[A]#reduceLeft

reduceLeft[B >: A](op: (B, A) => B): B

Python函数中的iterable arg对应Traversable实例,Python函数中的function arg对应op

请注意,还有一些名为reducereduceRightreduceLeftOptionreduceRightOption的方法,它们相似但略有不同。

折叠

您提供initializer arg的示例与Scala的Traversable[A]#foldLeft对应:

foldLeft[B](z: B)(op: (B, A) => B): B

Python函数中的initializer arg对应z中的foldLeft arg。

再次注意,有一些名为foldfoldRight的相关方法。

斐波

在不更改算法的情况下,这是代码的清理版本:

def fibonacci(position: Int): Seq[Int] =
  position match {
    case 1 => Vector(1)
    case 2 => Vector(1, 1)
    case _ =>
      (2 to position).foldLeft(Vector(1, 1)) { (series, _) =>
        series :+ (series(series.size - 1) + series(series.size - 2))
      }
  }

一些杂项说明:

  • 我们通常不会使用return关键字
  • 模式匹配(我们使用match关键字执行的操作)通常被认为比if - else链更清晰
  • 尽可能将var(允许多次转让)替换为val(不允许)
  • 如果您不需要,请不要使用可变集合(ArrayBuffer)。 Vector是一个很好的通用不可变序列。

虽然我们正在讨论馆藏和斐波那契系列的主题,但为了好玩,您可以查看Stream文档中的第一个示例:

val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #::
  fibs.zip(fibs.tail).map { n => n._1 + n._2 }

fibs.drop(1).take(6).mkString(" ")
// "1 1 2 3 5 8"