我想将List[Box[T]]
转换为Box[List[T]]
。
我知道我可以使用foldRight
,但我找不到优雅的方法。
编辑我想保留Box
的属性,也就是说,如果有任何失败,请返回Box
此失败。
答案 0 :(得分:2)
我不确定你为什么想要一个Box [List [T]],因为空列表应该足以表示缺少任何值。我认为这对你来说已经足够了。
我没有Lift方便的副本,但我知道Box的灵感来自Option并且有一个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 [Aither [A,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)
答案 1 :(得分:1)
使用尾递归函数比使用折叠更容易做到这一点:
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相关的答案。)