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