过滤 Scala Either 列表中的失败

Filtering a Scala Either list for failures

我有一个输入值列表

List[A]

和一个函数

f(List[A]): Either[Failure, Success]

我将函数应用于列表的每个元素,结果是 List[Either[Failure, Success]]

我想检查列表,如果有任何值失败,return 第一次失败,否则 return 成功列表。

我使用了以下模式:

val allValues = list.map(f(_))
if (allValues.exists(_.isLeft)) {
  allValues.find(_.isLeft).get
} else {
  allValues.collect {
    case Right(result) => result
  }
}

val allValues = list.map(f(_))
val failures = allValues.collect { case Left(error) => error }
if (failures.nonEmpty) {
  failures(0)
} else {
  allValues.collect {
    case Right(result) => result
  }
}

有没有更简洁的表达方式?

有时,我必须通过另一个函数进一步处理成功,再次使用相同的模式。例如

这应该有效

l.collectFirst { case Left(error) => error }.getOrElse {
     l.map(_.right)
 } 

其中 lEither[Left, Right]

的列表

例如:

万一出现错误

val l = List(Right(1), Right(2), Left(3), Left(4), Right(5))
l.collectFirst { case Left(error) => error }.getOrElse {
     l.map(_.right)
 } //res0: Any = 3

它 returns any 因为它可以 return FailureSuccess

的列表

听起来好像您想将 List[Either[Failure, Success]] 转换为 Either[Failure, List[Success]]?您可以使用 toLeft.

使它更优雅
result collectFirst { case Left(f) => f } toLeft {
    result collect { case Right(r) => r}
}

collectFirst 接受一个 PartialFunction[A, B] 它将应用于 List 的具有定义输出的第一个元素,并将 return Option[B] .在这种情况下,我尝试从 List 中提取第一个 Left(f),因此我将得到 Option[Failure].

然后,我在 Option[Failure] 上调用 toLeft。如果 Option 包含一个值,这将再次将单个 Failure 转换为 Left,如果 Option 为空,则参数将生成 Right 值。

如果 Option 确实为空,那么我使用 collect 提取成功,类似于使用 collectFirst,只是它保留了 List 的所有元素PartialFunction 是为

定义的