我想将List[Option[T]]
转换为Option[List[T]]
。函数的签名类型为
def lo2ol[T](lo: List[Option[T]]): Option[List[T]]
预期的行为是将仅包含
Some
的列表映射到包含元素Some
内的元素列表的Some
。另一方面,如果输入列表中至少有一个None
,则预期的行为是仅返回None
。例如:scala> lo2ol(Some(1) :: Some(2) :: Nil)
res10: Option[List[Int]] = Some(List(1, 2))
scala> lo2ol(Some(1) :: None :: Some(2) :: Nil)
res11: Option[List[Int]] = None
scala> lo2ol(Nil : List[Option[Int]])
res12: Option[List[Int]] = Some(List())
没有scalaz的示例实现为:
def lo2ol[T](lo: List[Option[T]]): Option[List[T]] = {
lo.foldRight[Option[List[T]]](Some(Nil)){(o, ol) => (o, ol) match {
case (Some(x), Some(xs)) => Some(x :: xs);
case _ => None : Option[List[T]];
}}}
我记得在某个地方看到过类似的示例,但是使用Scalaz简化了代码。看起来如何?
使用Scala2.8
PartialFunction.condOpt
的版本更为简洁,但仍然没有Scalaz:import PartialFunction._
def lo2ol[T](lo: List[Option[T]]): Option[List[T]] = {
lo.foldRight[Option[List[T]]](Some(Nil)){(o, ol) => condOpt(o, ol) {
case (Some(x), Some(xs)) => x :: xs
}
}}
最佳答案
有一个函数可以在Scalaz中将List[Option[A]]
转换为Option[List[A]]
。这是sequence
。要在所有元素均为None
的情况下获取None
,而在所有元素均为Some[List[A]]
的情况下获取Some
,则可以执行以下操作:
import scalaz.syntax.traverse._
import scalaz.std.list._
import scalaz.std.option._
lo.sequence
如果存在
F[G[A]
和G[F[A]]
的实现,则此方法实际上将Traverse[F]
转换为Applicative[G]
(Option
和List
恰好满足了这两个要求,并由这些导入提供)。Applicative[Option]
的语义是,如果List
的Option
的任何元素都是None
,那么sequence
也将是None
。如果要获取所有Some
值的列表,而不管是否有其他值是None
,则可以执行以下操作:lo flatMap (_.toList)
您可以对也形成
Monad
的任何Monoid
进行概括(List
恰好是其中之一):import scalaz.syntax.monad._
def somes[F[_],A](x: F[Option[A]])
(implicit m: Monad[F], z: Monoid[F[A]]) =
x flatMap (o => o.fold(_.pure[F])(z.zero))
关于scala - 使用Scalaz将选项列表转换为列表选项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2569014/