Michael
Michael

Reputation: 10303

How to "find" sequence element and predicate result at once?

Suppose I have a function f(n:Int):Option[String]. I would like to find such 1 <= k <= 10 that f(k) is not None. I can code it as follows:

(1 to 10).find(k => f(k).isDefined)

Now I would like to know both k and f(k).

val k = (1 to 10).find(f(_).isDefined)
val s = f(k)

Unfortunately, this code invokes f(k) twice. How would you find k and f(k) at once ?

Upvotes: 2

Views: 232

Answers (3)

Dave L.
Dave L.

Reputation: 9791

A slightly more verbose version of Tomasz Nurkiewicz's solution:

xs = (1 to 10).view      
xs zip { xs map { f(_) } } collectFirst { case (k, Some(v)) => (k, v) }

Upvotes: 2

user unknown
user unknown

Reputation: 36229

A bit shorter - just map and find:

// for testing
def f (n: Int): Option [String] = 
  if (n > 0) Some ((List.fill (n) ("" + n)).mkString) else None

(-5 to 5).map (i => (i, f(i))).find (e => e._2 != None) 

// result in REPL
res67: Option[(Int, Option[String])] = Some((1,Some(1)))

Upvotes: 2

Tomasz Nurkiewicz
Tomasz Nurkiewicz

Reputation: 340733

My first try would be:

(1 to 10).view map {k => (k, f(k))} find {_._2.isDefined}

The use of view avoids creating intermediate map. Or even better with pattern matching and partial function:

(1 to 10).view map {k => (k, f(k))} collectFirst {case (k, Some(v)) => (k, v)}

This returns Option[(Int, java.lang.String)] (None if no element satisfying f is found).

You might also experiment with .zipWithIndex.

Upvotes: 9

Related Questions