diff --git a/tutorials/tour/_posts/2017-02-13-for-comprehensions.md b/tutorials/tour/_posts/2017-02-13-for-comprehensions.md new file mode 100644 index 0000000000..cf9f4cf166 --- /dev/null +++ b/tutorials/tour/_posts/2017-02-13-for-comprehensions.md @@ -0,0 +1,51 @@ +--- +layout: tutorial +title: For Comprehensions + +disqus: true + +tutorial: scala-tour +categories: tour +num: 17 +next-page: generic-classes +previous-page: extractor-objects +--- + +Scala offers a lightweight notation for expressing *sequence comprehensions*. Comprehensions have the form `for (enumerators) yield e`, where `enumerators` refers to a semicolon-separated list of enumerators. An *enumerator* is either a generator which introduces new variables, or it is a filter. A comprehension evaluates the body `e` for each binding generated by the enumerators and returns a sequence of these values. + +Here's an example: + +```tut +case class User(val name: String, val age: Int) + +val userBase = List(new User("Travis", 28), + new User("Kelly", 33), + new User("Jennifer", 44), + new User("Dennis", 23)) + +val twentySomethings = for (user <- userBase if (user.age >=20 && user.age < 30)) + yield user.name // i.e. add this to a list + +twentySomethings.foreach(name => println(name)) // prints Travis Dennis +``` +The `for` loop used with a `yield` statement actually creates a `List`. Because we said `yield user.name`, it's a `List[String]`. `user <- userBase` is our iterator and `if (user.age >=20 && user.age < 30)` is a guard that filters out users who are in their 20s. + +Here is a more complicated example using two generators. It computes all pairs of numbers between `0` and `n-1` whose sum is equal to a given value `v`: + +```tut +def foo(n: Int, v: Int) = + for (i <- 0 until n; + j <- i until n if i + j == v) + yield (i, j) + +foo(10, 10) foreach { + case (i, j) => + print(s"($i, $j) ") // prints (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) +} + +``` +Here `n == 10` and `v == 10`. On the first iteration, `i == 0` and `j == 0` so `i + j != v` and therefore nothing is yielded. `j` gets incremented 9 more times before `i` gets incremented to `1`. Without the `if` guard, this would simply print the following: +``` + +(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 1) ... +``` diff --git a/tutorials/tour/_posts/2017-02-13-sequence-comprehensions.md b/tutorials/tour/_posts/2017-02-13-sequence-comprehensions.md deleted file mode 100644 index 5fa828e337..0000000000 --- a/tutorials/tour/_posts/2017-02-13-sequence-comprehensions.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -layout: tutorial -title: Sequence Comprehensions - -disqus: true - -tutorial: scala-tour -categories: tour -num: 17 -next-page: generic-classes -previous-page: extractor-objects ---- - -Scala offers a lightweight notation for expressing *sequence comprehensions*. Comprehensions have the form `for (enumerators) yield e`, where `enumerators` refers to a semicolon-separated list of enumerators. An *enumerator* is either a generator which introduces new variables, or it is a filter. A comprehension evaluates the body `e` for each binding generated by the enumerators and returns a sequence of these values. - -Here is an example: - -```tut -object ComprehensionTest1 extends App { - def even(from: Int, to: Int): List[Int] = - for (i <- List.range(from, to) if i % 2 == 0) yield i - Console.println(even(0, 20)) -} -``` - -The for-expression in function introduces a new variable `i` of type `Int` which is subsequently bound to all values of the list `List(from, from + 1, ..., to - 1)`. The guard `if i % 2 == 0` filters out all odd numbers so that the body (which only consists of the expression i) is only evaluated for even numbers. Consequently, the whole for-expression returns a list of even numbers. - -The program yields the following output: - -``` -List(0, 2, 4, 6, 8, 10, 12, 14, 16, 18) -``` - -Here is a more complicated example which computes all pairs of numbers between `0` and `n-1` whose sum is equal to a given value `v`: - -```tut -object ComprehensionTest2 extends App { - def foo(n: Int, v: Int) = - for (i <- 0 until n; - j <- i until n if i + j == v) yield - (i, j); - foo(20, 32) foreach { - case (i, j) => - println(s"($i, $j)") - } -} -``` - -This example shows that comprehensions are not restricted to lists. The previous program uses iterators instead. Every datatype that supports the operations `withFilter`, `map`, and `flatMap` (with the proper types) can be used in sequence comprehensions. - -Here's the output of the program: - -``` -(13, 19) -(14, 18) -(15, 17) -(16, 16) -``` - -There is also a special form of sequence comprehension which returns `Unit`. Here the bindings that are created from the list of generators and filters are used to perform side-effects. The programmer has to omit the keyword `yield` to make use of such a sequence comprehension. -Here's a program which is equivalent to the previous one but uses the special for comprehension returning `Unit`: - -``` -object ComprehensionTest3 extends App { - for (i <- Iterator.range(0, 20); - j <- Iterator.range(i, 20) if i + j == 32) - println(s"($i, $j)") -} -``` -