views:

114

answers:

3

I have a list l:List[T1] and currently im doing the following:

myfun : T1 -> Option[T2]
val x: Option[T2] = l.map{ myfun(l) }.flatten.find(_=>true)

The myfun function returns None or Some, flatten throws away all the None's and find returns the first element of the list if any.

This seems a bit hacky to me. Im thinking that there might exist some for-comprehension or similar that will do this a bit less wasteful or more clever. For example: I dont need any subsequent answers if myfun returns any Some during the map of the list l.

+3  A: 

Well, this is almost, but not quite

val x = (l flatMap myfun).headOption

But you are returning a Option rather than a List from myfun, so this may not work. If so (I've no REPL to hand) then try instead:

val x = (l flatMap(myfun(_).toList)).headOption
oxbow_lakes
+4  A: 

Well, the for-comprehension equivalent is pretty easy

(for(x<-l, y<-myfun(x)) yield y).headOption

which, if you actually do the the translation works out the same as what oxbow_lakes gave. Assuming reasonable laziness of List.flatmap, this is both a clean and efficient solution.

Dave Griffith
Unfortunately, List (i.e. collection.immutable.List) does not have lazy operations. For reasons I don't understand, replacing `l` with `l.view` results in myfun being evaluated multiple times with the same arguments.
Aaron Novstrup
view is call-by-name, not lazy. If you want at-most-once evaluation, use toStream:(l.toStream flatMap myfun).headOption
Martin Odersky
+3  A: 

How about:

l.toStream flatMap (myfun andThen (_.toList)) headOption

Stream is lazy, so it won't map everything in advance, but it won't remap things either. Instead of flattening things, convert Option to List so that flatMap can be used.

Daniel