I have some code like the below, where I have a list of Eithers, and I want to turn it into an Either of Lists ... in particular (in this case), if there are any Lefts in the list, then I return a Left of the list of them, otherwise I return a Right of the list of the rights.
val maybe: List[Either[String, Int]] = getMaybe val (strings, ints) = maybe.partition(_.isLeft) strings.map(_.left.get) match { case Nil => Right(ints.map(_.right.get)) case stringList => Left(stringList) }
Calling get
always makes me feel like I must be missing something.
Is there a more idiomatic way to do this?
data.partition(_.isLeft) match { case (Nil, ints) => Right(for(Right(i) <- ints) yield i) case (strings, _) => Left(for(Left(s) <- strings) yield s) }
For one pass:
data.partition(_.isLeft) match { case (Nil, ints) => Right(for(Right(i) <- ints.view) yield i) case (strings, _) => Left(for(Left(s) <- strings.view) yield s) }
Starting in Scala 2.13
, most collections are now provided with a partitionMap
method which partitions elements based on a function returning either Right
or Left
.
In our case, we don't even need a function that transforms our input into Right
or Left
to define the partitioning since we already have Right
s and Left
s. Thus a simple use of identity
!
Then it's just a matter of matching the resulting partitioned tuple of lefts and rights based on whether or not there are any lefts:
eithers.partitionMap(identity) match { case (Nil, rights) => Right(rights) case (lefts, _) => Left(lefts) } // * List[Either[String, Int]] = List(Right(3), Left("error x"), Right(7)) // => Either[List[String],List[Int]] = Left(List(error x)) // * List[Either[String, Int]] = List(Right(3), Right(7)) // => Either[List[String],List[Int]] = Right(List(3, 7))
For the understanding of partitionMap
here is the result of the intermediate step:
List(Right(3), Left("error x"), Right(7)).partitionMap(identity) // (List[String], List[Int]) = (List(error x), List(3, 7))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With