Reputation: 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?
Upvotes: 1
Views: 1081
Reputation: 51271
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.
Upvotes: 1
Reputation: 20561
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.
Upvotes: 2