稍微简化一下,我的问题来自一个字符串input
列表,我希望使用返回parse
的函数Either[String,Int]
进行解析。
然后list.map(parse)
会返回Either
的列表。该程序的下一步是格式化错误消息,总结传递在已解析整数列表中的所有错误或。
让我们调用我正在寻找的解决方案partitionEithers
。
调用
partitionEithers(List(Left("foo"), Right(1), Left("bar")))
会给予
(List("foo", "bar"),List(1))
在标准库中找到这样的东西是最好的。如果没有某种清洁,惯用和有效的解决方案,那将是最好的。还有一些高效的实用功能我可以粘贴到我的项目中就行了。
我在these 3 earlier questions之间感到非常困惑。据我所知,这些问题都不符合我的情况,但有些答案似乎包含了这个问题的有效答案。
答案 0 :(得分:6)
Scala集合提供partition
函数:
val eithers: List[Either[String, Int]] = List(Left("foo"), Right(1), Left("bar"))
eithers.partition(_.isLeft) match {
case (leftList, rightList) =>
(leftList.map(_.left.get), rightList.map(_.right.get))
}
=> res0: (List[String], List[Int]) = (List(foo, bar),List(1))
<强>更新强>
如果你想把它包装成一个(甚至有点类型更安全)的通用函数:
def partitionEither[Left : ClassTag, Right : ClassTag](in: List[Either[Left, Right]]): (List[Left], List[Right]) =
in.partition(_.isLeft) match {
case (leftList, rightList) =>
(leftList.collect { case Left(l: Left) => l }, rightList.collect { case Right(r: Right) => r })
}
答案 1 :(得分:4)
我并没有真正得到其他答案的扭曲量。所以这是一个班轮:
datediff()
答案 2 :(得分:3)
这是一个模仿Scala集合内部风格的命令式实现。
我想知道那里是否应该有这样的东西,因为至少我会不时遇到这种情况。
import collection._
import generic._
def partitionEithers[L, R, E, I, CL, CR]
(lrs: I)
(implicit evI: I <:< GenTraversableOnce[E],
evE: E <:< Either[L, R],
cbfl: CanBuildFrom[I, L, CL],
cbfr: CanBuildFrom[I, R, CR])
: (CL, CR) = {
val ls = cbfl()
val rs = cbfr()
ls.sizeHint(lrs.size)
rs.sizeHint(lrs.size)
lrs.foreach { e => evE(e) match {
case Left(l) => ls += l
case Right(r) => rs += r
} }
(ls.result(), rs.result())
}
partitionEithers(List(Left("foo"), Right(1), Left("bar"))) == (List("foo", "bar"), List(1))
partitionEithers(Set(Left("foo"), Right(1), Left("bar"), Right(1))) == (Set("foo", "bar"), Set(1))
答案 3 :(得分:3)
您可以使用separate
(scalaz)或MonadPlus
(猫)中的MonadCombine
:
import scala.util.{Either, Left, Right}
import scalaz.std.list._
import scalaz.std.either._
import scalaz.syntax.monadPlus._
val l: List[Either[String, Int]] = List(Right(1), Left("error"), Right(2))
l.separate
// (List[String], List[Int]) = (List(error),List(1, 2))
答案 4 :(得分:0)
您可以使用foldLeft。
def f(s: Seq[Either[String, Int]]): (Seq[String], Seq[Int]) = {
s.foldRight((Seq[String](), Seq[Int]())) { case (c, r) =>
c match {
case Left(le) => (le +: r._1, r._2)
case Right(ri) => (r._1 , ri +: r._2)
}
}
}
val eithers: List[Either[String, Int]] = List(Left("foo"), Right(1), Left("bar"))
scala> f(eithers)
res0: (Seq[String], Seq[Int]) = (List(foo, bar),List(1))