如何使用高阶函数展平选项列表?

发布于 2024-09-03 01:43:34 字数 1249 浏览 10 评论 0原文

使用 Scala 2.7.7:

如果我有一个选项列表,我可以使用 for 理解来展平它们:

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)

我不喜欢这种风格,宁愿使用 HOF。这种尝试过于冗长,无法接受:

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

直觉上我希望以下内容能够工作,但事实并非如此:

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

即使以下内容似乎应该工作,但事实并非如此:

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

我能想到的最好的办法是:

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

..但我宁愿不必将选项转换为列表。这看起来很笨重。

有什么建议吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

溇涏 2024-09-10 01:43:34

在 Scala 2.8 中,扁平化将起作用:


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)

但是,这在 2.7.7 中不起作用:


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

集合库已重新设计,并且在 2.8 中改进了很多,因此也许您可能想尝试使用最新的 Scala 2.8 RC 和看看这是否会让您更容易使用。

如果你真的不想使用 toList 方法,我想你也可以这样写:


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

也许也不是一件好事,但至少这在 2.7.7 中有效。

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.

怼怹恏 2024-09-10 01:43:34

为了补充 Arjan 的答案,在 Scala 2.7.7 中,您可以使用 List#flatten,但您需要帮助类型推断器:

Welcome to Scala version 2.7.7.final (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[String]                   
res0: List[String] = List(hi)

scala> val x: List[String] = listOfOptions.flatten
x: List[String] = List(hi)

To complement Arjan's answer, in Scala 2.7.7 you can use List#flatten, but you need to help out the type inferencer:

Welcome to Scala version 2.7.7.final (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[String]                   
res0: List[String] = List(hi)

scala> val x: List[String] = listOfOptions.flatten
x: List[String] = List(hi)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文