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])
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.
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.
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
.
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:
return
keywordmatch
keyword) is often considered cleaner than an if
-else
chainvar
(which allows multiple assignment) with val
(which doesn't) wherever possibleArrayBuffer
) 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"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With