将列表[[[A,B]之一]扁平化到列表[B],像列表[Option [B]]扁平化到列表[B]

Mar*_*lic 2 scala flatten either scala-cats

猫是否能提供类似于

implicit class FlattenListOfEither[L, R](l: List[Either[L, R]]) {
  def flattenM: List[R] = l collect { case Right(v) => v }
}
Run Code Online (Sandbox Code Playgroud)

这样

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

输出

List(1, 2, 4)
Run Code Online (Sandbox Code Playgroud)

类似于Vanilla Scala展平选项列表的方式

val l2: List[Option[Int]] = List(Some(1), Some(2), None, Some(4))
l2.flatten
Run Code Online (Sandbox Code Playgroud)

哪个输出

List(1, 2, 4)
Run Code Online (Sandbox Code Playgroud)

separate 提供以下语法

import cats.implicits._
val (_, rights) = l1.separate
rights
Run Code Online (Sandbox Code Playgroud)

哪个输出

List(1, 2, 4)
Run Code Online (Sandbox Code Playgroud)

但是,是否存在flatten类似开箱即用的扩展方法,该方法仅返回权限而不是元组?

Luk*_*itz 6

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

def mapFilter[A, B](fa: F[A])(f: (A) ? Option[B]): F[B]
Run Code Online (Sandbox Code Playgroud)

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

如果我们将此功能应用于您的列表,则只需将Either[A, B]s转换为Option[B]s。这就像调用一样简单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)
Run Code Online (Sandbox Code Playgroud)