I just found some notes from when I first began working with Scala, and I was working with the yield
keyword in for
loops. If you haven't worked with something like yield
before, it will help to know how it works. Here's a statement of how the yield
keyword works, from the book, Programming in Scala:
For each iteration of your for
loop, yield
generates a value which will be remembered. It's like the for
loop has a buffer you can’t see, and for each iteration of your for
loop another item is added to that buffer. When your for
loop finishes running, it will return this collection of all the yielded values. The type of the collection that is returned is the same type that you were iterating over, so a Map
yields a Map
, a List
yields a List
, and so on.
Also, note that the initial collection is not changed; the for/yield construct creates a new collection according to the algorithm you specify.
Basic for-loop examples
Given that background information, let’s look at a few for/yield examples. First, this example just yields a new collection that’s identical to the collection I’m looping over:
scala> for (i <- 1 to 5) yield i
res10: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5)
Nothing too exciting there, but it’s a start. Next, let’s double every element in our initial collection:
scala> for (i <- 1 to 5) yield i * 2
res11: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)
As another example, here’s what the Scala modulus operator does in a for/yield loop:
scala> for (i <- 1 to 5) yield i % 2
res12: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 0, 1, 0, 1)
for-loop/yield examples over a Scala Array
I mentioned in my description that the for loop yield construct returns a collection that is the same as the collection it is given. To demonstrate this, let’s look at the same examples with a Scala Array. Note the type of the collection that is yielded, and compare it to the previous examples:
scala> val a = Array(1, 2, 3, 4, 5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
scala> for (e <- a) yield e
res5: Array[Int] = Array(1, 2, 3, 4, 5)
scala> for (e <- a) yield e * 2
res6: Array[Int] = Array(2, 4, 6, 8, 10)
scala> for (e <- a) yield e % 2
res7: Array[Int] = Array(1, 0, 1, 0, 1)
As you can see, in these examples an Array[Int] was yielded, while in the earlier examples an IndexedSeq[Int] was returned.
for loop, yield, and guards (for-loop ‘if’ conditions)
If you’re familiar with the Scala for comprehension syntax, you know that you can add if statements to your for loop construct. Tests like these are often referred to as “guards,” and you can combine them with the yield syntax, as shown here:
scala> val a = Array(1, 2, 3, 4, 5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
scala> for (e <- a if e > 2) yield e
res1: Array[Int] = Array(3, 4, 5)
As you can see, adding the if e > 2 guard condition limits the Array we return to the three elements shown.
A real-world example
I don’t know if this will make sense out of context, but if you’d like to see a real-world use of a for/yield loop, here you go:
def getQueryAsSeq(query: String): Seq[MiniTweet] = {
val queryResults = getTwitterInstance.search(new Query(query))
val tweets = queryResults.getTweets // java.util.List[Status]
for (status <- tweets) yield ListTweet(status.getUser.toString,
status.getText, status.getCreatedAt.toString)
}
This code uses the JavaConversions package to convert the java.util.List[Status] I get back from Twitter4J into a Seq[MiniTweet]. The loop actually returns a Buffer[ListTweet], which is a Seq[ListTweet]. A MiniTweet is just a small version of a Twitter tweet, with the three fields shown.
Summary: Scala for-loop and yield examples
If you’re familiar with Scala’s for-loop construct, you know that there’s also much more work that can be performed in the first set of parentheses. You can add if
statements and other statements there, such as this example from the book Programming in Scala:
def scalaFiles =
for {
file <- filesHere
if file.getName.endsWith(".scala")
} yield file
I'll try to share more complicated examples like this in the future, but for today I wanted to share some simple for/yield examples, something like “An introduction to the Scala yield
keyword.”
Summary: Scala’s yield
keyword
As a quick summary of the yield
keyword:
- For each iteration of your for loop, yield generates a value which is remembered by the for loop (behind the scenes, like a buffer).
- When your for loop finishes running, it returns a collection of all these yielded values.
- The type of the collection that is returned is the same type that you were iterating over.
I hope these examples have been helpful. As usual, feel free to leave any questions, comments, or cool examples below.