首页 > 解决方案 > 将 List[Either[A, B]] 转换为 Either[List[A], List[B]]

问题描述

如何转换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)而不是 required Left(List(error1, error2))

KevinWrights 的回答建议

val lefts = xs collect {case Left(x) => x }
def rights = xs collect {case Right(x) => x}
if(lefts.isEmpty) Right(rights) else Left(lefts)

哪个返回Left(List(error1, error2)),但是猫是否提供开箱即用的排序来收集所有的左边?

标签: scalascala-cats

解决方案


同一主题的另一个变体(类似于此答案),所有导入包括:

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
}

如果你另外 import cats.syntax.either._,那么它toValidated变得可用,所以你也可以写:

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

如果你另外替换left.mapby bimap(..., identity),你最终会得到@DmytroMitin 非常简洁的解决方案。


推荐阅读