2014-10-26 16 views
15

Chcę podzielić List[Either[A, B]] na dwóch listach.Jak podzielić listę [Albo [A, B]]

Czy istnieje lepszy sposób?

def lefts[A, B](eithers : List[Either[A, B]]) : List[A] = eithers.collect { case Left(l) => l} 
def rights[A, B](eithers : List[Either[A, B]]) : List[B] = eithers.collect { case Right(r) => r} 

Odpowiedz

21

Nie wiem, to jest naprawdę dużo schludniej, ale:

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") 
+2

Edycja:. (., Lefts.map (_ left.get) rights.map (_ right.get)) staje (lefts.flatMap (_ left.toOption) rights.flatMap (_. right.toOption)) – Lombric

7

Można zrobić to z:

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))) 
1

Cóż, w przypadku, gdy nie musi być jeden -liner ... to może być nie myślenia.

def split[A,B](eithers : List[Either[A, B]]):(List[A],List[B]) = { 
    val lefts = scala.collection.mutable.ListBuffer[A]() 
    val rights = scala.collection.mutable.ListBuffer[B]() 
    eithers.map { 
    case Left(l) => lefts += l 
    case Right(r) => rights += r 
    } 
    (lefts.toList, rights.toList) 
} 

Ale, szczerze mówiąc, wolałbym odpowiedź Marth „s :)

7

Jeśli scalaz jest jednym z twoich zależności chciałbym po prostu użyć 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) 
+3

Chcesz zapewnić pełniejszą odpowiedź ze wszystkimi wymaganymi importami? A konkretna wersja scalaz? – noahlz

+1

'libraryDependencies + =" org.scalaz "%%" scalaz-core "%" 7.2.2 "' i "importuj scalaz.Scalaz._". więcej informacji: http://stackoverflow.com/questions/36878459/how-to-turn-a-list-of-sithers-to-a-either-of-lists-using-scalaz-monadplus-separa/36883766#36883766 –

+1

W przypadku, gdy używasz 'cats', masz też' oddzielne'! http://typelevel.org/cats/api/cats/syntax/SeparateOps.html#separate(implicitF:cats.MonadCombine[F],implicitG:cats.Bifoldable[G]):(F[A],F[B ]) –

5

kompaktowe, ale nie efekciarskie rozwiązanie:

val lefts = list.flatMap(_.left.toOption) 
val rights = list.flatMap(_.right.toOption) 
0

Nieco funkcjonalne rozwiązanie dla 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) 
    } 
    } 
} 
Powiązane problemy