Last active
October 28, 2021 17:35
-
-
Save programaker/3caec5646cd9b305f2c3c97f9dfee012 to your computer and use it in GitHub Desktop.
Scala List x LazyList x Iterator x View
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.util.Try | |
def compute(n: Int): Int = | |
val res = n * 10 | |
println(s">>> computing $n -> $res") | |
res | |
val n = 4 | |
val nth = 1 | |
/// | |
val list = Iterator.from(1).take(n).toList | |
// List is eager; the computation happens here and the collection will be traversed 3 times, once per `map` | |
val list2 = list.map(compute).map(compute).map(compute) | |
// As the entire List is already computed, we can get the nth element multiple times | |
val get1 = | |
Try(list2(nth)) | |
.flatMap(_ => Try(list2(nth))) | |
.flatMap(_ => Try(list2(nth))) | |
.flatMap(_ => Try(list2(nth))) | |
/* | |
>>> computing 1 -> 10 | |
>>> computing 2 -> 20 | |
>>> computing 3 -> 30 | |
>>> computing 4 -> 40 | |
>>> computing 10 -> 100 | |
>>> computing 20 -> 200 | |
>>> computing 30 -> 300 | |
>>> computing 40 -> 400 | |
>>> computing 100 -> 1000 | |
>>> computing 200 -> 2000 | |
>>> computing 300 -> 3000 | |
>>> computing 400 -> 4000 | |
val list: List[Int] = List(1, 2, 3, 4) | |
val list2: List[Int] = List(1000, 2000, 3000, 4000) | |
val get1: scala.util.Try[Int] = Success(2000) | |
*/ | |
/// | |
val lazyList = LazyList.from(1).take(n) | |
// LazyList is, well, lazy; nothing happens here | |
val lazyList2 = lazyList.map(compute).map(compute).map(compute) | |
// When we get the nth element, ```only the first n elements``` will be computed (and cached!) | |
// Due to lazyness, the collection will be traversed only once; the 3 `maps` are applied in the same step | |
// We can get the nth element multiple times, but the necessary computations won't happen again | |
val get2 = | |
Try(lazyList2(nth)) | |
.flatMap(_ => Try(lazyList2(nth))) | |
.flatMap(_ => Try(lazyList2(nth))) | |
.flatMap(_ => Try(lazyList2(nth))) | |
/* | |
>>> computing 1 -> 10 | |
>>> computing 10 -> 100 | |
>>> computing 100 -> 1000 | |
>>> computing 2 -> 20 | |
>>> computing 20 -> 200 | |
>>> computing 200 -> 2000 | |
val lazyList: LazyList[Int] = LazyList(1, 2, <not computed>) | |
val lazyList2: LazyList[Int] = LazyList(1000, 2000, <not computed>) | |
val get2: scala.util.Try[Int] = Success(2000) | |
*/ | |
/// | |
val iterator = Iterator.from(1).take(n) | |
// Iterator is lazy; nothing happens here | |
val iterator2 = iterator.map(compute).map(compute).map(compute) | |
// When we get the nth element, ```only the first n elements``` will be computed | |
// Due to lazyness, the collection will be traversed only once; the 3 `maps` are applied in the same step | |
// However, we can get the nth element only once; there's no turning back (and not even an apply method) | |
val get3 = Try(iterator2.drop(nth).next()) | |
/* | |
>>> computing 1 -> 10 | |
>>> computing 10 -> 100 | |
>>> computing 100 -> 1000 | |
>>> computing 2 -> 20 | |
>>> computing 20 -> 200 | |
>>> computing 200 -> 2000 | |
val iterator: Iterator[Int] = <iterator> | |
val iterator2: Iterator[Int] = <iterator> | |
val get3: scala.util.Try[Int] = Success(2000) | |
*/ | |
// Repeating the operation will just navigate the Iterator further ahead | |
// When we reach the end of the Iterator, a `NoSuchElementException` happens | |
val get31 = | |
get3 | |
.flatMap(_ => Try(iterator2.drop(nth).next())) | |
.flatMap(_ => Try(iterator2.drop(nth).next())) | |
.flatMap(_ => Try(iterator2.drop(nth).next())) | |
/* | |
>>> computing 3 -> 30 | |
>>> computing 30 -> 300 | |
>>> computing 300 -> 3000 | |
>>> computing 4 -> 40 | |
>>> computing 40 -> 400 | |
>>> computing 400 -> 4000 | |
val get31: scala.util.Try[Int] = Failure(java.util.NoSuchElementException: next on empty iterator) | |
*/ | |
/// | |
val view = Iterator.from(1).take(n).toList.view | |
// View is lazy; nothing happens here | |
val view2 = view.map(compute).map(compute).map(compute) | |
// When we get the nth element, ```only the nth element itself``` will be computed | |
// Due to lazyness, the collection will be traversed only once; the 3 `maps` are applied in the same step | |
// We can get the nth element multiple times, however, there is no cache and the computation will happen again | |
val get4 = | |
Try(view2(nth)) | |
.flatMap(_ => Try(view2(nth))) | |
.flatMap(_ => Try(view2(nth))) | |
.flatMap(_ => Try(view2(nth))) | |
/* | |
>>> computing 2 -> 20 | |
>>> computing 20 -> 200 | |
>>> computing 200 -> 2000 | |
>>> computing 2 -> 20 | |
>>> computing 20 -> 200 | |
>>> computing 200 -> 2000 | |
>>> computing 2 -> 20 | |
>>> computing 20 -> 200 | |
>>> computing 200 -> 2000 | |
>>> computing 2 -> 20 | |
>>> computing 20 -> 200 | |
>>> computing 200 -> 2000 | |
val view: scala.collection.SeqView[Int] = SeqView(<not computed>) | |
val view2: scala.collection.SeqView[Int] = SeqView(<not computed>) | |
val get4: scala.util.Try[Int] = Success(2000) | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment