将Seq [[String,Int]]转换为(Seq [String],Seq [Int])的高效和/或惯用方法

Pet*_*erg 2 scala either

略微简化,我的问题来自一个字符串列表input,我想用函数parse返回解析Either[String,Int].

然后list.map(parse)返回一个Eithers 列表.该程序的下一步是格式化错误消息,总结所有错误传递解析的整数列表.

让我们来称呼我正在寻找的解决方案partitionEithers.

调用

partitionEithers(List(Left("foo"), Right(1), Left("bar")))
Run Code Online (Sandbox Code Playgroud)

会给

(List("foo", "bar"),List(1))
Run Code Online (Sandbox Code Playgroud)

在标准库中找到这样的东西是最好的.如果没有某种清洁,惯用和有效的解决方案,那将是最好的.还有一些高效的实用功能我可以粘贴到我的项目中就行了.

对这 3个早期 问题感到非常困惑.据我所知,这些问题都不符合我的情况,但有些答案似乎包含了这个问题的有效答案.

Sas*_*erg 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))
Run Code Online (Sandbox Code Playgroud)

UPDATE

如果你想将它包装在一个(甚至有点类型更安全)的泛型函数中:

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 })
}
Run Code Online (Sandbox Code Playgroud)


Pet*_*ens 5

您可以使用separatefrom MonadPlus(scalaz) 或MonadCombine(cats) :

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))
Run Code Online (Sandbox Code Playgroud)