5.2
Write the function take(n) for returning the first n elements of a Stream, and drop(n) for skipping the first n elements of a Stream.
Note: The key to remember here is that since in take we need to create another stream and keep the elements in order. While in drop, we drop from the head of the stream and return the rest
Solution
object Solution extends App {
val stream: Stream[Int] = Stream(1,2,3,4,5,6)
println("Stream:" + stream.toList)
val take3: Stream[Int] = stream.take(3)
println("take(3):" + take3.toList)
val drop3: Stream[Int] = stream.drop(3)
println("drop(3):" + drop3.toList)
}
import scala.annotation
trait Stream[+A] {
import Stream._
def take(n: Int): Stream[A] = this match {
case Empty => empty
case Cons(h, t) if n > 1 => cons(h(), t().take(n-1))
case Cons(h, t) if n == 1 => cons(h(), empty)
}
def drop(n: Int): Stream[A] = {
@annotation.tailrec
def go(s: Stream[A], n: Int): Stream[A] = s match {
case Empty => s
case Cons(h, t) if n >= 1 => go(t(), n - 1)
case Cons(h, t) if n == 0 => s
}
go(this, n)
}
def toList: List[A] = {
@annotation.tailrec
def go(l: List[A], s: Stream[A]): List[A] = s match {
case Empty => l.reverse
case Cons(h,t) => go(h()::l, t())
}
go(List(), this)
}
}
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
object Stream {
def empty[A]: Stream[A] = Empty
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = {
lazy val head = hd
lazy val tail = tl
Cons(() => head, () => tail)
}
def apply[A](as: A*): Stream[A] =
if(as.isEmpty) empty else cons(as.head, apply(as.tail: _*))
}
Output
Stream:List(1, 2, 3, 4, 5, 6)
take(3):List(1, 2, 3)
drop(3):List(4, 5, 6)