Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
858 views
in Technique[技术] by (71.8m points)

scala - How to flatten list of options using higher order functions?

Using Scala 2.7.7:

If I have a list of Options, I can flatten them using a for-comprehension:

val listOfOptions = List(None, Some("hi"), None)
listOfOptions: List[Option[java.lang.String]] = List(None, Some(hi), None)

scala> for (opt <- listOfOptions; string <- opt) yield string
res0: List[java.lang.String] = List(hi)

I don't like this style, and would rather use a HOF. This attempt is too verbose to be acceptable:

scala> listOfOptions.flatMap(opt => if (opt.isDefined) Some(opt.get) else None)
res1: List[java.lang.String] = List(hi)

Intuitively I would have expected the following to work, but it doesn't:

scala> List.flatten(listOfOptions)
<console>:6: error: type mismatch;
 found   : List[Option[java.lang.String]]
 required: List[List[?]]
       List.flatten(listOfOptions)

Even the following seems like it should work, but doesn't:

scala> listOfOptions.flatMap(_: Option[String])
<console>:6: error: type mismatch;
 found   : Option[String]
 required: (Option[java.lang.String]) => Iterable[?]
       listOfOptions.flatMap(_: Option[String])
                          ^

The best I can come up with is:

scala> listOfOptions.flatMap(_.toList)         
res2: List[java.lang.String] = List(hi)

... but I would much rather not have to convert the option to a list. That seems clunky.

Any advice?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In Scala 2.8, flatten will work:


Welcome to Scala version 2.8.0.RC2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.

scala> val listOfOptions = List(None, Some("hi"), None)
listOfOptions: List[Option[java.lang.String]] = List(None, Some(hi), None)

scala> listOfOptions flatten
res0: List[java.lang.String] = List(hi)

This doesn't work in 2.7.7, however:


Welcome to Scala version 2.7.7.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20).

scala> val listOfOptions = List(None, Some("hi"), None)
listOfOptions: List[Option[java.lang.String]] = List(None, Some(hi), None)

scala> listOfOptions.flatten
:6: error: no implicit argument matching parameter type (Option[java.lang.String]) => Iterable[Nothing] was found.
       listOfOptions.flatten

The collections library has been redesigned, and has improved a lot in 2.8, so perhaps you might want to try to use the latest Scala 2.8 RC and see if that makes it more easy to use for you.

If you really don't want to use the toList method, I guess you can also write it like this:


scala> listOfOptions.flatMap(o => o)
res: List[java.lang.String] = List(hi)

Also not a thing of beauty perhaps, but at least this works in 2.7.7.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...