将 Scala `Seq[Option[A]]` 转换为 `Option[Seq[A]]`

Convert Scala `Seq[Option[A]]` to `Option[Seq[A]]`

我想知道在 Scala 中将 Option[A]Seq 转换为 Option[Seq[A]] 的惯用方式是什么,如果有的话,结果是 None的输入选项是 None.

惯用的方式大概就是用一般所谓的traverse.

我建议阅读有关它的 Cats 文档:https://typelevel.org/cats/typeclasses/traverse.html

有了 Cats,它就像:

import cats.implicits

val list = List(Some(1), Some(2), None)
// list: List[Option[Int]] = List(Some(1), Some(2), None)

val traversed = list.traverse(identity)
// traversed: Option[List[Int]] = None

// Or in this specific case:
val sequenced = list.sequence
// sequenced: Option[List[Int]] = None

标准库提供 partitionMap 帮助实现 sequence 操作

_.partitionMap(_.toRight("")) match {
  case (Nil, xs) => Some(xs)
  case _ => None
}

这是一个可能的通用实现作为扩展方法

extension [CC[x] <: IterableOps[x, CC, CC[x]], A](xs: CC[Option[A]])
  def sequence: Option[CC[A]] =
    xs.partitionMap(_.toRight("")) match {
        case (lefts, as) if lefts.isEmpty => Some(as)
        case _ => None
    }