Scala Liftweb-将列表[Box[T]]转换为框[List[T]]
我想将Scala Liftweb-将列表[Box[T]]转换为框[List[T]],scala,lift,scala-collections,Scala,Lift,Scala Collections,我想将List[Box[T]]转换为Box[List[T]] 我知道我可以使用foldRight,但我找不到一种优雅的方式来使用它 编辑我想保留框的属性,也就是说,如果出现任何故障,请返回一个带有此故障的框。如果您只想收集“完整”值 我不确定您为什么想要一个框[List[T]],因为空的列表应该足以表示缺少任何值。我想这对你来说已经足够了 我手边没有Lift的副本,但我知道Box的灵感来自Option,并且有一个平面图方法,因此: 长格式: for { box <- list va
List[Box[T]]
转换为Box[List[T]]
我知道我可以使用foldRight
,但我找不到一种优雅的方式来使用它
编辑我想保留框的属性
,也就是说,如果出现任何故障,请返回一个带有此故障的框。如果您只想收集“完整”值
我不确定您为什么想要一个框[List[T]],因为空的列表应该足以表示缺少任何值。我想这对你来说已经足够了
我手边没有Lift的副本,但我知道Box的灵感来自Option,并且有一个平面图方法,因此:
长格式:
for {
box <- list
value <- box
} yield value
最短形式:
list.flatten
如果您也想收集故障:
下面是我用来解决这类问题的mapSplit
函数。您可以轻松地将其调整为使用框
,而不是或:
/**
* 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[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)
如果您只想收集“完整”值
我不确定您为什么想要一个框[List[T]],因为空的列表应该足以表示缺少任何值。我想这对你来说已经足够了
我手边没有Lift的副本,但我知道Box的灵感来自Option,并且有一个平面图方法,因此:
长格式:
for {
box <- list
value <- box
} yield value
最短形式:
list.flatten
如果您也想收集故障:
下面是我用来解决这类问题的mapSplit
函数。您可以轻松地将其调整为使用框
,而不是或:
/**
* 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[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)
使用尾部递归函数比使用折叠函数更容易:
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中的答案。)使用尾部递归函数比使用折叠函数更容易做到这一点:
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中的答案。)希望这是他想要的……还有“如果有None
,列表是None
”版本。可能是这样,但foldRight通常不用于提前终止。@AlexCruise如果有故障,我希望保留这些故障。也就是说,如果列表中有一个失败对象,我想返回那个对象。在您的结果中,EmptyBox
对象被忽略了,我想。希望这是他想要的……还有“如果有None
,列表是None
”版本。可能是这样,但是foldRight通常不用于提前终止。@如果有,我希望保留失败。也就是说,如果列表中有一个失败对象,我想返回那个对象。在您的结果中,EmptyBox
对象被忽略。类似的,它在同一个头脑中,但您无法链接选项,我不希望使用Scalaz。类似的,它在同一个头脑中,但您无法链接选项,我不希望使用Scalaz。