Scala map only right value and display error for left

Viewed 314

I have a sequence of left and right values like:

val l: Seq[Either[Error, Data]] = Seq(Left(Error), Right(Data), ...)

I want to map all Right values and display the error for a Left. I have tried:

val data: Seq[Data] = l.flatMap {
  case Right(data) => data
  case Left(err)   => println(err) // doesn't work because println is Unit
}

Any way to do this?

2 Answers

It's generally not a great practice to mix side effects and pure code like this, but something like (assuming a strict Seq):

def rightsAfterEffectingLefts[A, B](eithers: Seq[Either[A, B]])(effect: A => Unit): Seq[B] = {
  eithers.foreach(_.left.foreach(effect))
  eithers.flatMap(_.toOption)
}

val data = rightsAfterEffectingLefts(l)(println _)

It's possible to optimize to avoid the double iteration, though you'd likely want to approach different Seq implementations differently.

EDIT: after Luis's suggestion

def rightsAfterEffectingLefts[A, B](eithers: Seq[Either[A, B]])(effect: A => Unit): Seq[B] = {
  val (lefts, rights) = eithers.partition(_.isLeft)
  lefts.foreach(_.left.foreach(effect))
  rights.flatMap(_.toOption)
}

is an alternative definition. It still double iterates and will likely be slower.

You were on the right track, just need to let flatMap() remove the Error after it's been printed.

val data: Seq[Data] = l.flatMap {
  case Right(data) => Some(data)
  case Left(err)   => println(err); None
}

A single traversal is all that's needed.

Related