我想将List[Box[T]]转换为Box[List[T]]。
我知道我可以使用foldRight,但我找不到一种优雅的方法来做到这一点。
编辑I希望保留Box的属性,也就是说,如果出现故障,则返回带有此故障的Box。
发布于 2012-03-15 17:45:07
与折叠函数相比,使用尾递归函数更容易做到这一点:
final def flip[T](l: List[Option[T]], found: List[T] = Nil): Option[List[T]] = l match {
case Nil => if (found.isEmpty) None else Some(found.reverse)
case None :: rest => None
case Some(x) :: rest => flip(rest, x :: found)
}这项工作如预期的那样:
scala> flip(List(Some(3),Some(5),Some(2)))
res3: Option[List[Int]] = Some(List(3, 5, 2))
scala> flip(List(Some(1),None,Some(-1)))
res4: Option[List[Int]] = None使用Iterator.iterate也可以做到这一点,但是它更尴尬和更慢,所以在这种情况下我会避免使用这种方法。
(另见我在问题4e6中的回答。)
发布于 2012-03-15 16:46:55
如果您只想收集“完整”值
我不知道您为什么要使用Box[ListT],因为空列表应该足以说明缺少任何值。我想这对你来说已经够好了。
我手头没有Lift的副本,但我知道Box是受选项启发的,并且有一个flatMap方法,因此:
长形式:
for {
box <- list
value <- box
} yield value较短的形式:
list.flatMap(identity)最短表格:
list.flatten如果您也想收集故障:
下面是我针对这类问题使用的mapSplit函数。您可以很容易地将它修改为使用Box而不是Either。
/**
* Splits the input list into a list of B's and a list of C's, depending on which type of value the mapper function returns.
*/
def mapSplit[A,B,C](in: Traversable[A])(mapper: (A) ⇒ Either[B,C]): (Seq[B], Seq[C]) = {
@tailrec
def mapSplit0(in: Traversable[A], bs: Vector[B], cs: Vector[C]): (Seq[B], Seq[C]) = {
in match {
case t if t.nonEmpty ⇒
val a = t.head
val as = t.tail
mapper(a) match {
case Left(b) ⇒ mapSplit0(as, bs :+ b, cs )
case Right(c) ⇒ mapSplit0(as, bs, cs :+ c)
}
case t ⇒
(bs, cs)
}
}
mapSplit0(in, Vector[B](), Vector[C]())
}当我只想分割一些已经是Seq[EitherA,B]的东西时,我使用以下方法:
/**
* Splits a List[Either[A,B]] into a List[A] from the lefts and a List[B] from the rights.
* A degenerate form of {@link #mapSplit}.
*/
def splitEither[A,B](in: Traversable[Either[A,B]]): (Seq[A], Seq[B]) = mapSplit(in)(identity)https://stackoverflow.com/questions/9724171
复制相似问题