Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Folding over a list of Options to Find First or Last Some

Tags:

scala

folding

I'm trying to fold over a list of Options in order return the first(or last) Some value or None if there aren't any Some values.

scala> val opts = List(None, Some(1), None, Some(2), None)
opts: List[Option[Int]] = List(None, Some(1), None, Some(2), None)

scala> opts foldLeft(None)((a,io) => a match { case None => io; case Some(i) =>
a})
<console>:9: error: object None does not take parameters
              opts foldLeft(None)((a,io) => a match { case None => io; case Some
(i) => a})
                                 ^

Not sure what I'm doing wrong. Also there is probably a way to do this simpler using a higher order function but nothing from here caught my eye.

like image 649
Trevor Avatar asked Nov 07 '11 16:11

Trevor


People also ask

What is fold left and fold right?

Both methods recursively combine items into another item. foldLeft combines items from left one to right one, on the other hand foldRight does this from right one to left one.

What is the difference between fold and reduce?

Fold and reduce The difference between the two functions is that fold() takes an initial value and uses it as the accumulated value on the first step, whereas the first step of reduce() uses the first and the second elements as operation arguments on the first step.

How does fold left work?

The foldLeft method takes an associative binary operator function as parameter and will use it to collapse elements from the collection. The order for traversing the elements in the collection is from left to right and hence the name foldLeft. The foldLeft method allows you to also specify an initial value.

What is the use of fold in Scala?

The fold method takes two sets of arguments. One contains a start value and the other a combining function. It then steps through the list, recursively applying the function to two operands: an accumulated value and the next element in the list.


2 Answers

Maybe this can solve your problem - the first element:

opts.flatten.headOption

And the last element:

opts.flatten.lastOption

flatten method will unbox all Option values in the list and drop all None values. headOption/lastOption will return either Some for the first/last element in the list or None if list is empty.

like image 152
tenshi Avatar answered Sep 22 '22 21:09

tenshi


tenshi’s answer is pretty straightforward but for long lists it will attempt to flatten everything as it isn’t lazy. (I think view won’t help us here either but I’m not quite sure.)

In that case, you could use:

opts.dropWhile(_.isEmpty).headOption.flatMap(identity)

Unfortunately, we cannot use flatten here as this will return a generic Iterable[Int] and no Option, so we have to chose the longer idiom flatMap(identity).

Edit: As dave noticed:

opts.find(_.isDefined).flatMap(identity)

would be even better.

like image 36
Debilski Avatar answered Sep 23 '22 21:09

Debilski