How to split a List[Either[A, B]]

前端 未结 8 1110
南笙
南笙 2020-12-10 11:01

I want to split a List[Either[A, B]] in two lists.

Is there a better way ?

def lefts[A, B](eithers : List[Either[A, B]]) : List[A] = eit         


        
相关标签:
8条回答
  • 2020-12-10 11:20

    You can do it with:

    val (lefts, rights) = eithers.foldRight((List[Int](), List[String]()))((e, p) => e.fold(l => (l :: p._1, p._2), r => (p._1, r :: p._2)))
    
    0 讨论(0)
  • 2020-12-10 11:23

    A somewhat functional solution for Seq.

    def partition[A, B](seq: Seq[Either[A, B]]): (Seq[A], Seq[B]) = {
      seq.foldLeft[(Seq[A], Seq[B])]((Nil, Nil)) { case ((ls, rs), next) =>
        next match {
          case Left(l) => (ls :+ l, rs)
          case Right(r) => (ls, rs :+ r)
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-10 11:24

    If scalaz is one of your dependencies I would simply use separate:

    import scalaz.std.list._
    import scalaz.std.either._
    import scalaz.syntax.monadPlus._
    
    val el : List[Either[Int, String]] = List(Left(1), Right("Success"), Left(42))
    
    scala> val (lefts, rights) = el.separate
    lefts: List[Int] = List(1, 42)
    rights: List[String] = List(Success)
    
    0 讨论(0)
  • 2020-12-10 11:26

    A compact, but not CPU-effictive solution:

    val lefts = list.flatMap(_.left.toOption)
    val rights = list.flatMap(_.right.toOption)
    
    0 讨论(0)
  • 2020-12-10 11:26

    If you're going to bother to abstract the functionality, as in Marth's answer, then it may actually make more sense to use roterl's solution:

    def splitEitherList[A,B](el: List[Either[A,B]]): (List[A], List[B]) =
      (el :\ (List[A](), List[B]()))((e, p) =>
        e.fold(l => (l :: p._1, p._2), r => (p._1, r :: p._2)))
    
    val x = List(Left(1), Right(3), Left(2), Left(4), Right(8))
    splitEitherList(x) // (List(1, 2, 4), List(3, 8))
    

    This way awards more functional brownie points, but also may be more performant, as it makes use of a right fold to create the lists in one pass

    But if you're doing it on the fly and/or find folds difficult to read, then by all means

    el.partition(_.isLeft) match { case (lefts, rights) =>
      (lefts.map(_.left.get), rights.map(_.right.get)) }
    
    0 讨论(0)
  • 2020-12-10 11:41

    Not sure this is really much neater, but :

    scala> def splitEitherList[A,B](el: List[Either[A,B]]) = {
             val (lefts, rights) = el.partition(_.isLeft)
             (lefts.map(_.left.get), rights.map(_.right.get))
           }
    splitEitherList: [A, B](el: List[Either[A,B]])(List[A], List[B])
    
    scala> val el : List[Either[Int, String]] = List(Left(1), Right("Success"), Left(42))
    el: List[Either[Int,String]] = List(Left(1), Right(Success), Left(42))
    
    scala> val (leftValues, rightValues) = splitEitherList(el)
    leftValues: List[Int] = List(1, 42)
    rightValues: List[String] = List("Success")
    
    0 讨论(0)
提交回复
热议问题