简体   繁体   中英

Is there an equivalent to python reduce() function in scala?

I've just started learning Scala and functional programming and I'm trying to convert the following from Python to 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])

I can't figure out what the equivalent of reduce in Scala is. This is what I currently have. Everything works fine except the last line.

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

Summary of Python reduce , for reference:

reduce(function, iterable[, initializer])

Traversable

A good type to look at is Traversable , a supertype of ArrayBuffer . You may want to just peruse that API for a while, because there's a lot of useful stuff in there.

Reduce

The equivalent of Python's reduce , when the initializer arg is omitted, is Scala's Traversable[A]#reduceLeft :

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

The iterable arg from the Python function corresponds to the Traversable instance, and the function arg from the Python function corresponds to op .

Note that there are also methods named reduce , reduceRight , reduceLeftOption , and reduceRightOption , which are similar but slightly different.

Fold

Your example, which does provide an initializer arg, corresponds to Scala's Traversable[A]#foldLeft :

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

The initializer arg from the Python function corresponds to the z arg in foldLeft .

Again, note that there are some related methods named fold and foldRight .

Fibonacci

Without changing the algorithm, here's a cleaned-up version of your code:

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

A few miscellaneous notes:

  • We generally never use the return keyword
  • Pattern matching (what we're doing with the match keyword) is often considered cleaner than an if - else chain
  • Replace var (which allows multiple assignment) with val (which doesn't) wherever possible
  • Don't use a mutable collection ( ArrayBuffer ) if you don't need to. Vector is a good general-purpose immutable sequence.

And while we're on the topic of collections and the Fibonacci series, for fun you may want to check out the first example in the Stream documentation:

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"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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