I feel insertSortRight is less efficient than insertSortLeft because insertSortRight needs to call List.last (which is O(n)) as one of the arguments to insert(), where insertSortLeft calls List.head (which is O(1)) as one of the arguments to insert().
Is this understanding correct? Thanks.
def insertSortRight(unsorted: List[Int]) : List[Int] = {
(unsorted :\ List[Int]()) ((a, b) => insert(a, b))
}
def insertSortLeft(unsorted: List[Int]) : List[Int] = {
(List[Int]() /: unsorted) ((a, b) => insert(b, a))
}
def insert(a: Int, list: List[Int]) : List[Int] = list match {
case List() => List(a)
case y::ys => if (a > y) y::insert(a, ys) else a::y::ys
}
DHG answered "always prefer left folding". But, Programming in Scala has an example the other way.
def flattenLeft[T](xss: List[List[T]]) = (List[T]() /: xss) (_ ::: )
def flattenRight[T](xss: List[List[T]]) = (xss :~List[T]()) ( ::: _)
I guess that is because flattenRight in this case is achieved by just one function call, while flattenLeft is achieved by n function call?
So, for a List, since head operations are desired, foldLeft is the natural choice. That way you work through the list from left to right, always taking the head. As you can see, its implementation (on LinearSeqOptimized) simply uses a while-loop and traverses once.
override /*TraversableLike*/
def foldLeft[B](z: B)(f: (B, A) => B): B = {
var acc = z
var these = this
while (!these.isEmpty) {
acc = f(acc, these.head)
these = these.tail
}
acc
}
It seems like 'foldRight' would be O(n^2) since, in order to take the last element, you have to traverse the n elements of the List n times, but the library actually optimizes this for you. Behind the scenes, foldRight is implemented like this (also on LinearSeqOptimized):
def foldRight[B](z: B)(f: (A, B) => B): B =
if (this.isEmpty) z
else f(head, tail.foldRight(z)(f))
As you can see, this function is constructed by recursively calling foldRight on the tail, holding each head on the stack, and applying the function to each head in reverse order after reaching the last element.
Related
I'm learning Scala. Now I have this code snippet:
sealed abstract class BSTree {
def fold[A](init: A)(f: (A, Int) => A): A = this match {
case Empty => init
case Node(left, data, right) =>
val curInorder:A = f(left.fold(init)(f), data)
right.fold(curInorder)(f)
}
}
case object Empty extends BSTree
case class Node(left: BSTree, data: Int, right: BSTree) extends BSTree
My aim is to add another method toList in class BSTree, which is on top
of method fold and build a List from the binary tree's inorder traversal.
My current implementation is:
sealed abstract class BSTree {
def fold[A](init: A)(f: (A, Int) => A): = .....//code snippet skipped
def toList: List[Int] =
fold(Nil: List[Int])((xs: List[Int], hd)=> hd::xs).reverse
}
But I feel that building a List and then reversing it is ugly. Is there a more elegant approach?
Any hints are appreciated.
First of all, your fold is not tail recursive which for large input might result in StackOverflowException. I'd encourage you to try out and implement it on your own using Stack. For reference I'll place a sample implementation at the bottom of my post.
Secondly, as it was already mentioned in comments - you might want to use ListBuffer so that building your list is more efficient in reversed order (thus, there is no need to reverse it back).
Here's a one-liner:
def toList: List[Int] = fold(ListBuffer.empty[Int])(_ += _).toList
And the the reference for implementing tail-recursive fold:
def fold[B](init: B)(op: (B, A) => B): B = {
def go(stack: List[(A, Tree[A])], current: Tree[A], acc: B): B = (current, stack) match {
case (Empty, Nil) => acc
case (Empty, (d, r) :: xs) => go(xs, r, op(acc, d))
case (Node(l, d, r), _) => go((d, r) +: stack, l, acc)
}
go(Nil, this, init)
}
I find that simply using xs :+ hd instead of hd::xs puts the values in the correct order (depth-first, left-to-right).
val testTree: BSTree =
Node(Node(Empty, 0, Empty), 1, Node(Empty, 2, Node(Node(Empty, 3, Empty), 4, Empty)))
def toList(bSTree: BSTree): List[Int] =
bSTree.fold(List[Int]())((acc, next) => acc :+ next)
toList(testTree) // List(0,1,2,3,4)
My implementation above is O(n²). We can improve it to O(n) by using a ListBuffer, as per #dkim's comment, or we can use Vector and then convert to List when we're done.
Apart from simply fixing the toList method, we might ask why the result of using fold to implement toList didn't agree with our intuition (giving us a backwards list instead of a forwards list). One might point out that the fold signature for list matches the structure of the List class hierarchy.
abstract class List[+A] {
def fold[B](init: B)(step: (A, B) => B): B
}
case object Empty extends List[Nothing] {
def fold[B](init: B)(step: (A, B) => B): B = init
}
case class Cons[+A](head: A, tail: List[A]) extends List[A] {
def fold[B](init: B)(step: (A, B) => B): B =
step(head, tail.fold(init)(step))
}
Notice how the method signature of fold matches the class hierarchy, even down to the values that each implementing class holds. (Aside: For purposes of brevity, I am using a very naive implementation of fold that is neither efficient nor stack safe. Production implementations should be tail recursive or use a loop and a mutable buffer, but the point is that the method signature would be the same.)
We can do the same for your BSTree class, the fold signature would be:
abstract class BSTree {
def fold[A](withEmpty: A)(withNode: (A, Int, A) => A): A
}
Then toList would be tree.fold(List[Int]())((l, n, r) => l ++ List(n) ++ r). But again, use a buffer or Vector to get decent performance if you anticipate tree being even about 50 entries or so.
I'm working on a Functional Programming in Scala exercise to implement foldRight on a Stream.
Before getting to that exercise, let me show how I've implemented foldLeft.
def foldLeft[A, B](as: Stream[A])(z: B)(f: (B, A) => B): B = {
def go(bs: Stream[A], acc: B) : B = bs match {
case x #:: xs => go(xs, f(acc, x))
case Stream() => acc
}
}
My understanding is that, via #::, I'm executing the fold in a tail-recursive and stream-y fashion, i.e. the tail isn't fully evaluated.
However, when I thought of how to implement foldRight, I figured I could simply do:
stream.reverse.foldLeft(monoid.zero)(monoid.op)
However, calling reverse will result in full evaluation of the stream:
scala> val x = Stream(1,2,3)
x: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> x.reverse
res15: scala.collection.immutable.Stream[Int] = Stream(3, 2, 1)
How can I stream-ily implement foldRight?
As part of an exercise from FP in Scala, I'm working on the implementation of foldLeft on an IndexedSeq.
I wrote 2 functions:
def foldLeft[A, B](as: IndexedSeq[A])(z: B)(f: (B, A) => B): B = {
def go(bs: IndexedSeq[A], acc: B): B = {
if (bs.isEmpty) acc
else go(bs.tail, f(acc, bs.head))
}
go(as, z)
}
And, then the pattern match way:
def foldLeftPM[A, B](as: IndexedSeq[A])(z: B)(f: (B, A) => B): B = {
def go(bs: IndexedSeq[A], acc: B): B = bs match {
case x +: xs => go(xs, f(acc, x))
case _ => acc
}
go(as, z)
}
EDIT Note that I got the +: operator from dhgs's answer. It appears to be a member of IndexedSeq's class or its parent since it's available without defining per the linked post.
Is either way better (from a performance or idiomatic Scala point of view)?
The pattern match is definitely more idiomatic.
For performance, they should be about the same, since they are exactly equivalent.
Though only benchmarking would decide, and that includes a lot of assumptions.
Continuing to work on Functional Programming in Scala exercises, I'm working on implementing foldRight on an IndexedSeq type.
Since foldRight will evaluate with right associativity, I created the following operator for pattern matching.
object :++ {
def unapply[T](s: Seq[T]) = s.lastOption.map(last =>
(last, s.take(s.length - 1)))
}
And then implemented as so:
object IndexedSeqFoldable extends Foldable[IndexedSeq] {
override def foldRight[A, B](as: IndexedSeq[A])(z: B)(f: (A, B) => B): B = {
def go(bs: Seq[A], acc: B): B = bs match {
case x :++ xs => go(xs, f(x, acc))
case _ => acc
}
go(as, z)
}
Ignoring the fact that foldRight can be written with foldLeft, how does my approach hold up?
How can I recurse through a Map?
I'm looking for something similar to list recursion, shown below.
def count(list: List[Int]): Int = {
def go(list: List[Int], acc: Int)) = {
case x :: xs => go(xs, x + sum)
case Nil => sum
}
go(list, 0)
}
Please ignore the fact that fold or reduce could be used here. I'm mentioning this tail-recursive function as a sample as to what I'd like for recursing through a map. I want to be able to append to an accumulator argument when recursing through a map.
You can turn the Map into a Seq with .toSeq or .toList or similar, or you can define your own Map extractor, but the easiest is to just use head and tail directly.
def recursive[A, B](map: Map[A, B]): Int =
if (map.isEmpty) 0 else helper(map)
def helper[A, B](map: Map[A, B]): Int = (map.head, map.tail) match {
case ((a, b), xs) if xs.isEmpty => 1
case ((a, b), xs) => 1 + helper(xs)
}