使用Scalaz将选项列表转换为列表选项 [英] Convert a List of Options to an Option of List using Scalaz
问题描述
我想将List[Option[T]]
转换为Option[List[T]]
.该函数的签名类型为
I want to transform a List[Option[T]]
into a Option[List[T]]
. The signature type of the function is
def lo2ol[T](lo: List[Option[T]]): Option[List[T]]
预期的行为是将仅包含Some
的列表映射到包含元素Some
内的元素列表的Some
中.另一方面,如果输入列表中至少有一个None
,则预期的行为是仅返回None
.例如:
The expected behavior is to map a list that contains only Some
s into a Some
containing a list of the elements inside the elements Some
's. On the other hand, if the input list has at least one None
, the expected behavior is to just return None
. For example:
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的示例实现为:
An example implementation, without scalaz, would be:
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简化了代码.看起来如何?
I remember seeing somewhere a similar example, but using Scalaz to simplify the code. How would it look like?
使用Scala2.8 PartialFunction.condOpt
的简洁版本,但仍然没有Scalaz:
A slightly more succinct version, using Scala2.8 PartialFunction.condOpt
, but still without 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
的情况下获取Some[List[A]]
,则可以执行以下操作:
There's a function that turns a List[Option[A]]
into an Option[List[A]]
in Scalaz. It's sequence
. To get None
in case any of the elements are None
and a Some[List[A]]
in case all the elements are Some
, you can just do this:
import scalaz.syntax.traverse._
import scalaz.std.list._
import scalaz.std.option._
lo.sequence
给定存在Traverse[F]
和Applicative[G]
的实现,此方法实际上将F[G[A]
转换为G[F[A]]
(Option
和List
恰好满足了这两个要求,并由这些导入提供).
This method actually turns F[G[A]
into G[F[A]]
given that there exists an implementation of Traverse[F]
, and of Applicative[G]
(Option
and List
happen to satisfy both and are provided by those imports).
Applicative[Option]
的语义是,如果Option
的List
的任何元素是None
,那么sequence
也将是None
.如果要获取所有Some
值的列表,而不管是否有其他值是None
,则可以执行以下操作:
The semantics of Applicative[Option]
are such that if any of the elements of a List
of Option
s are None
, then the sequence
will be None
as well. If you want to get a list of all the Some
values regardless of whether any other values are None
, you can do this:
lo flatMap (_.toList)
您可以概括地说,对于也形成Monoid
的任何Monad
(List
恰好是其中之一):
You can generalize that for any Monad
that also forms a Monoid
(List
happens to be one of these):
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))
这篇关于使用Scalaz将选项列表转换为列表选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!