将 List[Either[A, B]] 扁平化为 List[B] 就像 List[Option[B]] 到 List[B]

Flatten List[Either[A, B]] to List[B] like List[Option[B]] to List[B]

猫是否提供类似于

的扁平化
implicit class FlattenListOfEither[L, R](l: List[Either[L, R]]) {
  def flattenM: List[R] = l collect { case Right(v) => v }
}

这样

val l1: List[Either[String, Int]] = List(Right(1), Right(2), Left("error"), Right(4))
l1.flattenM

产出

List(1, 2, 4)

类似于 vanilla Scala 扁平化选项列表的方式

val l2: List[Option[Int]] = List(Some(1), Some(2), None, Some(4))
l2.flatten

输出

List(1, 2, 4)

separate 给出以下语法

import cats.implicits._
val (_, rights) = l1.separate
rights

输出

List(1, 2, 4)

然而,是否存在开箱即用的 flatten 类扩展方法,returns 只是权限而不是元组?

Scala 2.13中的partitionMap呢? (请注意 shorter 是什么意思):

   val l1: List[Either[String, Int]] = List(Right(1), Right(2), Left("error"), Right(4))
    val (_, rights) = l1.partitionMap(identity)
    println(rights)
 // Displays
 // List(1, 2, 4)

我认为最简单的方法是使用 FunctorFilter 类型类提供的 mapFilter。 它看起来像这样:

def mapFilter[A, B](fa: F[A])(f: (A) ⇒ Option[B]): F[B]

其中 F[A] 可以是 List[A],或 Vector[A] 或任何其他允许过滤的类型。

如果我们将此函数应用于您的列表,我们只需要将 Either[A, B] 转换为 Option[B] 即可。这就像调用 toOption 一样简单。 完整的解决方案如下所示:

import cats.implicits._

val l1: List[Either[String, Int]] = List(Right(1), Right(2), Left("error"), Right(4))

l1.mapFilter(_.toOption)
// List(1, 2, 4)

我只想说

listOfEithers.flatMap(_.toOption)

使用普通的香草 Scala 收集方法似乎可以满足您的要求:

val x = List(Right(1), Right(2), Left("error"), Right(4))
x.flatMap(_.toOption) // res0: List[Int] = List(1, 2, 4)