使用案例
我有一个文件列表,这些文件可能具有有效的mime类型。 在我的代码中,我使用Option来表示。
我需要将Seq [Option [T]]转换为Option [Seq [T]],以便在某些文件无效的情况下不处理列表。
错误
这是以下实现中的错误:
struct B {
typedef void(A::*pointer)(int,int);
pointer f;
void set_handler(pointer p) { f = p; }
};
int main() {
{
B object1;
object2.set_handler(&A::fun);
}
{
B object2;
object2.set_handler(&A::fun1);
}
}
实施
boost::bind()
此实现返回found : (Option[Seq[A]], Option[A]) => Option[Seq[A]]
[error] required: (Option[Any], Option[Any]) => Option[Any]
[error] s.fold(init)(liftOptionItem[A])
而不是def liftOptionItem[A](acc: Option[Seq[A]], itemOption: Option[A]): Option[Seq[A]] = {
{
acc match {
case None => None
case Some(items) =>
itemOption match {
case None => None
case Some(item) => Some(items ++ Seq(item))
}
}
}
}
def liftOption[A](s: Seq[Option[A]]): Option[Seq[A]] = {
s.fold(Some(Seq()))(liftOptionItem[A])
}
,因为Option[Any]
的类型不合适。
答案 0 :(得分:1)
如果您使用TypeLevel Cats:
import cats.implicits._
List(Option(1), Option(2), Option(3)).traverse(identity)
返回:
Option[List[Int]] = Some(List(1, 2, 3))
您必须使用List
,所以请先使用toList
:
Seq(Option(1), Option(2), Option(3)).toList.traverse(identity).map(_.toSeq)
答案 1 :(得分:1)
使用scalaz:
import scalaz._
import Sclaza._
val x:List[Option[Int]] = List(Option(1))
x.sequence[Option, Int] //returns Some(List(1))
val y:List[Option[Int]] = List(None, Option(1))
y.sequence[Option, Int] // returns None
答案 2 :(得分:0)
尾递归解决方案:如果seq元素中的任何一个为None,则返回None。
def seqToOption[T](s: Seq[Option[T]]): Option[Seq[T]] = {
@tailrec
def seqToOptionHelper(s: Seq[Option[T]], accum: Seq[T] = Seq[T]()): Option[Seq[T]] = {
s match {
case Some(head) :: Nil => Option(head +: accum)
case Some(head) :: tail => seqToOptionHelper(tail, head +: accum)
case _ => None
}
}
seqToOptionHelper(s)
}
答案 3 :(得分:0)
以case语句处理None
是代替Option[Seq[Any]] type
返回Option[Seq[A]] type
的原因。我们需要使功能
liftOptionItem[A]
返回Option[Seq[Any]] type
。并且可以通过对两个函数进行以下更改来解决编译错误。(由于fold
的执行顺序没有特定限制,因此start value
受到约束,因此return value
受到限制。使用foldLeft
代替fold
。)
def liftOptionItem[A](acc: Option[Seq[Any]], itemOption: Option[A]): Option[Seq[Any]] = {
{
acc match {
case None => Some(Nil)
case Some(items)=>
itemOption match {
case None => Some(items ++ Seq("None"))
case Some(item) => Some(items ++ Seq(item))
}
}
}
}
def liftOption[A](s: Seq[Option[A]]): Option[Seq[Any]] = {
s.foldLeft(Option(Seq[Any]()))(liftOptionItem[A])
}
现在,代码会编译。
在Scala REPL中:
scala> val list1 = Seq(None,Some(21),None,Some(0),Some(43),None)
list1: Seq[Option[Int]] = List(None, Some(21), None, Some(0), Some(43), None)
scala> liftOption(list1)
res2: Option[Seq[Any]] = Some(List(None, 21, None, 0, 43, None))
scala> val list2 = Seq(None,Some("String1"),None,Some("String2"),Some("String3"),None)
list2: Seq[Option[String]] = List(None, Some(String1), None, Some(String2), Some(String3), None)
scala> liftOption(list2)
res3: Option[Seq[Any]] = Some(List(None, String1, None, String2, String3, None))
答案 4 :(得分:0)
如果您不想使用cats或Scalaz之类的功能库,则可以使用foldLeft
def seqToOpt[A](seq: Seq[Option[A]]): Option[Seq[A]] =
seq.foldLeft(Option(Seq.empty[A])){
(res, opt) =>
for {
seq <- res
v <- opt
} yield seq :+ v
}