others - scala - 将列表List[Either[A, B]] 转换为Either[List[A], List[B]]

134 2

如何使用类似于cat sequence的方法将List[Either[String, Int]]转换为Either[List[String], List[Int]]? 例如,像以下代码中的xs.sequence


import cats.implicits._


val xs: List[Either[String, Int]] = List(Left("error1"), Left("error2"))


xs.sequence



返回Left(error1)而不是Left(List(error1, error2)) 。


val lefts = xs collect {case Left(x) => x }


def rights = xs collect {case Right(x) => x}


if(lefts.isEmpty) Right(rights) else Left(lefts)



时间: 原作者:

85 0


import scala.util.Either


import cats.data.Validated


import cats.syntax.traverse._


import cats.instances.list._



def collectErrors[A, B](xs: List[Either[A, B]]): Either[List[A], List[B]] = {


 xs.traverse(x => Validated.fromEither(x.left.map(List(_)))).toEither


}



如果另外导入cats.syntax.either._,则toValidated可用,因此你也可以写成:


xs.traverse(_.left.map(List(_)).toValidated).toEither



原作者:
107 2

try


xs.traverse(_.toValidated.bimap(List(_), identity)).toEither



// List(Left("error1"), Left("error2")) => Left(List("error1","error2"))


// List(Right(10), Right(20)) => Right(List(10, 20))


// List(Right(10), Left("error2")) => Left(List("error2"))



原作者:
73 4

你可以使用.separate()将列表分割为一个元组(List[String], List[Int]),并且匹配:


scala> xs.separate match {


 case (Nil, rights) => Right(rights)


 case (lefts, _) => Left(lefts)


 }


res0: scala.util.Either[List[String],List[Int]] = Left(List(error1, error2))



原作者:
150 3

此解决方案不使用cats,在Scala 2.13中,你可以使用partitionMap :


 def convert[L,R](input: List[Either[L,R]]): Either[List[L], List[R]] = {


 val (left, right) = input.partitionMap(identity)


 if (left.isEmpty) Right(right) else Left(left)


 }



 println(convert(List(Left("error1"), Left("error2"))))


 // Left(List(error1, error2))


 println(convert(List(Right(1), Left("2"), Right(3), Left("4"))))


 // Left(List(2, 4))


 println(convert(List(Right(1), Right(2), Right(3), Right(4))))


 // Right(List(1, 2, 3, 4))



原作者:
...