How to reduce Seq[Either[A,B]] to Either[A,Seq[B]]?

前端 未结 8 1379
孤城傲影
孤城傲影 2020-12-05 01:31

Given a sequence of eithers Seq[Either[String,A]] with Left being an error message. I want to obtain an Either[String,Seq[A]] where I

相关标签:
8条回答
  • 2020-12-05 02:27

    My answer is similar to @Garrett Rowe's: But it uses foldLeft (Also see: Why foldRight and reduceRight are NOT tail recursive?) and prepends to Seq rather than appending to Seq (See: Why is appending to a list bad?).

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    def partitionEitherSeq[A,B](eitherSeq: Seq[Either[A,B]]): (Seq[A], Seq[B]) =
      eitherSeq.foldLeft(Seq.empty[A], Seq.empty[B]) { (acc, next) =>
      val (lefts, rights) = acc
      next.fold(error => (lefts :+ error, rights), result => (lefts, rights :+ result))
    }
    
    // Exiting paste mode, now interpreting.
    
    partitionEitherSeq: [A, B](eitherSeq: Seq[Either[A,B]])(Seq[A], Seq[B])
    
    scala> partitionEitherSeq(Seq(Right("Result1"), Left("Error1"), Right("Result2"), Right("Result3"), Left("Error2")))
    res0: (Seq[java.lang.String], Seq[java.lang.String]) = (List(Error1, Error2),List(Result1, Result2, Result3))
    
    0 讨论(0)
  • 2020-12-05 02:28

    Building on Kevin's solution, and stealing a bit from Haskell's Either type, you can create a method partitionEithers like so:

    def partitionEithers[A, B](es: Seq[Either[A, B]]): (Seq[A], Seq[B]) =
      es.foldRight (Seq.empty[A], Seq.empty[B]) { case (e, (as, bs)) =>
        e.fold (a => (a +: as, bs), b => (as, b +: bs))
      }
    

    And use that to build your solution

    def unroll[A, B](es: Seq[Either[A, B]]): Either[Seq[A], Seq[B]] = {
      val (as, bs) = partitionEithers(es)
      if (!as.isEmpty) Left(as) else Right(bs)
    }
    
    0 讨论(0)
提交回复
热议问题