【问题标题】:Flatten List[Either[A, B]] to List[B] like List[Option[B]] to List[B]将 List[Either[A, B]] 展平到 List[B] 就像 List[Option[B]] 到 List[B]
【发布时间】:2019-12-09 12:09:17
【问题描述】:

猫是否提供类似于

的扁平化
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 类扩展方法,它只返回权限而不是元组?

【问题讨论】:

  • 我怀疑这种方法是否存在。对于像 Monads 这样的一般抽象来说,它没有任何意义,因为您需要一种方法来将任何嵌套元素视为与外部相同类型的元素。使用选项的情况有效,因为在 stdlib 上,Option 可以隐式 转换为 IterabeOnce (只有一个元素) - 老实说我不喜欢这样,但那是另一个讨论。现在,如果它是一种仅适用于内部 Eithers 的特殊方法,那么 separate 是更有意义的方法 - 恕我直言,最好是使用 collect

标签: scala flatten scala-cats either


【解决方案1】:

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

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

其中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)

【讨论】:

    【解决方案2】:

    我只是想说一下

    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)
    

    【讨论】:

    • 如果使用香草,我个人觉得collect { case Right(v) => v } 更清晰,但我觉得flatten 完美地传达了这个概念(如果它存在的话)
    • @MarioGalic 我不知道。我发现 LukaJacobowitz 的mapFiltercollect 略短且更好,但后来我发现flatMap 看起来几乎像mapFilter,但不需要我在文档中查找它,但我又看到@ 987654329@ 比flatMap 表达意图更清晰。它是圆形的,就像石头剪刀布一样,不知道我更喜欢哪一个:D
    【解决方案3】:

    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)
    
    

    【讨论】:

    • 更短,我的意思是它只返回权限而不是元组。
    猜你喜欢
    • 2019-10-23
    • 2018-06-29
    • 1970-01-01
    • 2016-09-16
    • 2021-04-03
    • 2011-12-03
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    相关资源
    最近更新 更多