首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Liftweb -将List[Box[T]]转换为Box[List[T]]

Liftweb -将List[Box[T]]转换为Box[List[T]]
EN

Stack Overflow用户
提问于 2012-03-15 16:40:18
回答 2查看 351关注 0票数 0

我想将List[Box[T]]转换为Box[List[T]]

我知道我可以使用foldRight,但我找不到一种优雅的方法来做到这一点。

编辑I希望保留Box的属性,也就是说,如果出现故障,则返回带有此故障的Box

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-03-15 17:45:07

与折叠函数相比,使用尾递归函数更容易做到这一点:

代码语言:javascript
复制
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)
}

这项工作如预期的那样:

代码语言:javascript
复制
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中的回答。)

票数 1
EN

Stack Overflow用户

发布于 2012-03-15 16:46:55

如果您只想收集“完整”值

我不知道您为什么要使用Box[ListT],因为空列表应该足以说明缺少任何值。我想这对你来说已经够好了。

我手头没有Lift的副本,但我知道Box是受选项启发的,并且有一个flatMap方法,因此:

长形式:

代码语言:javascript
复制
for {
  box <- list
  value <- box
} yield value

较短的形式:

代码语言:javascript
复制
list.flatMap(identity)

最短表格:

代码语言:javascript
复制
list.flatten

如果您也想收集故障:

下面是我针对这类问题使用的mapSplit函数。您可以很容易地将它修改为使用Box而不是Either

代码语言:javascript
复制
/**
 * 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]的东西时,我使用以下方法:

代码语言:javascript
复制
/**
 * 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)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9724171

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档