|
| 1 | +--- |
| 2 | +layout: tutorial |
| 3 | +title: For Comprehensions |
| 4 | + |
| 5 | +disqus: true |
| 6 | + |
| 7 | +tutorial: scala-tour |
| 8 | +categories: tour |
| 9 | +num: 17 |
| 10 | +next-page: generic-classes |
| 11 | +previous-page: extractor-objects |
| 12 | +--- |
| 13 | + |
| 14 | +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. |
| 15 | + |
| 16 | +Here's an example: |
| 17 | + |
| 18 | +```tut |
| 19 | +case class User(val name: String, val age: Int) |
| 20 | +
|
| 21 | +val userBase = List(new User("Travis", 28), |
| 22 | + new User("Kelly", 33), |
| 23 | + new User("Jennifer", 44), |
| 24 | + new User("Dennis", 23)) |
| 25 | +
|
| 26 | +val twentySomethings = for (user <- userBase if (user.age >=20 && user.age < 30)) |
| 27 | + yield user.name // i.e. add this to a list |
| 28 | +
|
| 29 | +twentySomethings.foreach(name => println(name)) // prints Travis Dennis |
| 30 | +``` |
| 31 | +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. |
| 32 | + |
| 33 | +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`: |
| 34 | + |
| 35 | +```tut |
| 36 | +def foo(n: Int, v: Int) = |
| 37 | + for (i <- 0 until n; |
| 38 | + j <- i until n if i + j == v) |
| 39 | + yield (i, j) |
| 40 | +
|
| 41 | +foo(10, 10) foreach { |
| 42 | + case (i, j) => |
| 43 | + print(s"($i, $j) ") // prints (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) |
| 44 | +} |
| 45 | +
|
| 46 | +``` |
| 47 | +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: |
| 48 | +``` |
| 49 | +
|
| 50 | +(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 1) ... |
| 51 | +``` |
0 commit comments