如何拆分列表[[A,B]]

时间:2014-10-26 18:38:46

标签: scala either

我想将List[Either[A, 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}

8 个答案:

答案 0 :(得分:23)

不确定这是否真的更整洁,但是:

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

答案 1 :(得分:13)

如果... for day in range(7): bugsToday = input('How many bugs did you get on day %d ?' % day) totalBugs = totalBugs + bugsToday ... 是您的某个依赖项,我只需使用scalaz

separate

答案 2 :(得分:8)

你可以用:

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

答案 3 :(得分:6)

紧凑但不具备CPU效率的解决方案:

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

答案 4 :(得分:5)

final ProductAdapter adapter = new ProductAdapter(this, productList, numberItemValues); 开始,现在大多数集合都提供了partitionMap方法,该方法根据返回Scala 2.13Right的函数对元素进行分区。

在我们的情况下,我们甚至不需要一个将输入转换为LeftRight来定义分区的函数,因为我们已经有Left和{{1} } s。因此,可以简单地使用Right

Left

答案 5 :(得分:1)

好吧,万一它不必是一个单行...那么它可以是一个明智的选择。

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

但是,说实话,我更喜欢 Marth 的回答:)

答案 6 :(得分:0)

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

答案 7 :(得分:0)

如果您要像Marth的答案那样去抽象功能,那么实际上使用roterl的解决方案可能更有意义:

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

这种方式可以奖励更多的功能性布朗尼蛋糕,但由于使用了正确的折痕,可以一次通过创建列表,因此其性能可能更高。

但是,如果您是即时进行的和/或发现难以阅读的折痕,那么一定要

el.partition(_.isLeft) match { case (lefts, rights) =>
  (lefts.map(_.left.get), rights.map(_.right.get)) }