使用日志记录过滤一组 Either[x, y]

Filtering a set of Either[x, y], with logging

给定 Set[Either[BadObject, GoodObject]],我想将其转换为 Set[GoodObject],同时记录所有 BadObjects

我遇到的问题是,当我尝试在 collect 调用中添加登录时,例如:

someMethodThatReurnsTheSet.collect {
  case Right(value) => value
  case Left(res) => logger.warn(s"Bad object : $res")
}

这会更改 return 值,我得到 Set[None],这不是我想要的。

简单方法:

someMethodThatReurnsTheSet().collect {
  case Right(value) => Some(value)
  case Left(res) => 
    logger.warn(s"Bad object : $res")
    None
}.flatten

很多替代方案都是可能的,例如或查看其他答案:)

val (lefts, rights) = someMethodThatReurnsTheSet().partition(_.isLeft)
lefts.foreach(err => logger.warn(s"Bad object : ${err.left.get}"))
val set = rights.map(_.right.get)

使用foldLeft的另一种方式:

someMethodThatReturnsTheSet.foldLeft(Set.empty[GoodObject]) {
   case (acc, goodOrBad) => goodOrBad match {
     case Right(good) => acc + good
     case Left(bad) => 
       logger.warn("Bad object: $bad")
       acc
   }
}

如果您不介意分配:

someMethodThatReturnsTheSet.flatMap {
  case Right(good) => Set(good)
  case Left(bad) => 
    logger.warn("Bad object: $bad")
    Set.empty
}

尝试partition in combination with chaining

import util.chaining._

someMethodThatReurnsTheSet
  .partition(_.isRight)
  .tap { case (_, lefts) => logger.warn(s"Bad objects $lefts") }
  .pipe { case (rights, _) => rights }

如果你只想在Left情况下采取行动,你可以使用.left.foreach:

setOfEithers.flatMap { e =>
    e.left.foreach { bad => logger.warn(s"Bad object: $bad") }
    e.toOption
}