在Scala中是否有类似于Python reduce()函数的等效函数?

4

我刚刚开始学习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))
}

最后一行有什么问题?你是否收到编译器错误(如果是,是什么),错误的结果(如果是,它们是什么,为什么是错误的),运行时错误(如果是,是什么)...? - Nathan Davis
1个回答

10

Python reduce的摘要 , 仅供参考:

reduce(function, iterable[, initializer])

可遍历

一个值得关注的类型是可遍历,它是ArrayBuffer的超类型。你可能想花一些时间浏览该API,因为其中有很多有用的东西。

Reduce

当省略initializer参数时,相当于Python中的reduce函数,Scala中的等价函数是可遍历[A]#reduceLeft

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

Python函数中的iterable参数对应于Traversable实例,而Python函数中的function参数对应于op

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

Fold

您的示例提供了一个initializer参数,对应于Scala的Traversable[A]#foldLeft

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

Python函数中的initializer参数对应于foldLeft中的z参数。

再次注意,还有一些相关的方法名为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"

2
或者,仅供比较,到目前为止我遇到的最简洁的斐波那契“Stream”:val fib: Stream[BigInt] = 0#:: fib.scan(1:BigInt)(_ + _) - jwvh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接