【问题标题】:Is there an equivalent to python reduce() function in scala?scala中是否有等效于python reduce()函数?
【发布时间】:2017-01-21 19:31:51
【问题描述】:

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

【问题讨论】:

  • 最后一行有什么问题?您是否收到编译器错误(如果是,它是什么)、不正确的结果(如果是,它们是什么以及它们为什么错误)、运行时错误(如果是,它是什么),...?

标签: python scala lambda functional-programming reduce


【解决方案1】:

Python总结reduce,供参考:

reduce(function, iterable[, initializer])

可遍历

一个很好的类型是TraversableArrayBuffer 的超类型。您可能只想仔细研究一下该 API,因为其中有很多有用的东西。

减少

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

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

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

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

折叠

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

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

Python 函数中的initializer arg 对应于foldLeft 中的z 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"

【讨论】:

  • 或者,只是为了比较,我遇到过(到目前为止)最简洁的斐波那契Streamval fib: Stream[BigInt] = 0 #:: fib.scan(1:BigInt)(_+_)
猜你喜欢
  • 2011-06-28
  • 1970-01-01
  • 2016-01-08
  • 1970-01-01
  • 2019-09-17
  • 2012-11-06
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多