Michael
Michael

Reputation: 42050

How to map and find lazily in Scala?

Suppose I have a list xs: List[X] and functions f(x:X):Y and g(y):Boolean. Now I need to find the first y = f(x) so that g(y) == true.

def findY(xs: List[X], f: X => Y, g: Y => Boolean): Option[Y] = ???

I can do it with xs.map(f).find(g) but I don't want to traverse the whole list xs. I don't want to use streams either. How would you suggest implement findY ?

Upvotes: 1

Views: 170

Answers (3)

Kigyo
Kigyo

Reputation: 5768

Another possibility would be to use collectFirst, which also returns an Option.

xs.collectFirst{case x if g(f(x)) => f(x)}

The only downside is that you evaluate f(x) twice if you find something that matches. I'm not sure if it is somehow possible to bind the result f(x) to some variable.

Upvotes: 1

Beryllium
Beryllium

Reputation: 12998

Instead of

xs.map(f).find(g)

just turn it around

xs.find(x => g(f(x)))

In both cases Option[X] is returned.


If you want Option[Y], a recursive method would do the job:

  @tailrec
  def findFirst[X, Y](xs: List[X], f: X => Y, g: Y => Boolean): Option[Y] = {
    xs match {
      case Nil =>
        None

      case h :: t =>
        val y = f(h)

        if (g(y)) {
          Some(y)
        } else {
          findFirst(t, f, g)
        }
    }
  }

Upvotes: 1

Luigi Plinge
Luigi Plinge

Reputation: 51109

Use a view

xs.view.map(f).find(g)

Upvotes: 8

Related Questions