How to yield a single element from for loop in scala?

scala

Solution

If you want to use a `for` loop, which uses a nicer syntax than chained invocations of `.find`, `.filter`, etc., there is a neat trick. Instead of iterating over strict collections like list, iterate over lazy ones like iterators or streams. If you're starting with a strict collection, make it lazy with, e.g. `.toIterator`.

Let's see an example.

First let's define a "noisy" int, that will show us when it is invoked

def noisyInt(i : Int) = () => { println("Getting %d!".format(i)); i }

Now let's fill a list with some of these:

val l = List(1, 2, 3, 4).map(noisyInt)

We want to look for the first element which is even.

val r1 = for(e <- l; val v = e() ; if v % 2 == 0) yield v

The above line results in:

Getting 1!
Getting 2!
Getting 3!
Getting 4!
r1: List[Int] = List(2, 4)

...meaning that all elements were accessed. That makes sense, given that the resulting list contains all even numbers. Let's iterate over an iterator this time:

val r2 = (for(e <- l.toIterator; val v = e() ; if v % 2 == 0) yield v)

This results in:

Getting 1!
Getting 2!
r2: Iterator[Int] = non-empty iterator

Notice that the loop was executed only up to the point were it could figure out whether the result was an empty or non-empty iterator.

To get the first result, you can now simply call `r2.next`.

If you want a result of an `Option` type, use:

if(r2.hasNext) Some(r2.next) else None

Edit Your second example in this encoding is just:

val seven = (for {
    x <- (1 to 10).toIterator
    if x == 7
} yield x).next

...of course, you should be sure that there is always at least a solution if you're going to use `.next`. Alternatively, use `headOption`, defined for all `Traversable`s, to get an `Option[Int]`.

Problem

Much like this question: Functional code for looping with early exit Say the code is ``` def findFirst[T](objects: List[T]):T = { for (obj <- objects) { if (expensiveFunc(obj) != null) return /*???*/ Some(obj) } None } ``` How to yield a single element from a for loop like this in scala? I do not want to use find, as proposed in the original question, i am curious about if and how it could be implemented using the for loop. * UPDATE * First, thanks for all the comments, but i guess i was not clear in the question. I am shooting for something like this: ``` val seven = for { x <- 1 to 10 if x == 7 } return x ``` And that does not compile. The two errors are: - return outside method definition - method main has return statement; needs result type I know find() would be better in this case, i am just learning and exploring the language. And in a more complex case with several iterators, i think finding with for can actually be usefull. Thanks commenters, i'll start a bounty to make up for the bad posing of the question :)

Original source

Related problems