如何通过谓词将一个序列分成两部分?

如何通过谓词将一个序列拆分为两个列表?

备选方案: 我可以使用 filterfilterNot,或者编写自己的方法,但是难道没有更好的通用(内置)方法吗?

60649 次浏览

使用 partition方法:

scala> List(1,2,3,4).partition(x => x % 2 == 0)
res0: (List[Int], List[Int]) = (List(2, 4),List(1, 3))

你可能想看看 Scalex.org-它允许你在 scala 标准库中通过函数的签名来搜索函数。例如,键入以下内容:

List[A] => (A => Boolean) => (List[A], List[A])

你会看到 分区

很好,partition正是您想要的——还有一种方法也使用谓词将列表分成两部分: span

在第一个列表中,分区将把所有“ true”元素放在一个列表中,其他元素放在第二个列表中。

Span 将把所有元素放在一个列表中,直到一个元素为“ false”(就谓词而言)。从这一点开始,它将把元素放在第二个列表中。

scala> Seq(1,2,3,4).span(x => x % 2 == 0)
res0: (Seq[Int], Seq[Int]) = (List(),List(1, 2, 3, 4))

如果需要一些额外的东西,也可以使用 foldLeft。我只是写了一些像这样的代码,当分区没有削减它:

val list:List[Person] = /* get your list */
val (students,teachers) =
list.foldLeft(List.empty[Student],List.empty[Teacher]) {
case ((acc1, acc2), p) => p match {
case s:Student => (s :: acc1, acc2)
case t:Teacher  => (acc1, t :: acc2)
}
}

如果您希望将一个列表分成两个以上的部分,并忽略边界,那么可以使用类似的方法(如果需要搜索 int,则可以进行修改)

def split(list_in: List[String], search: String): List[List[String]] = {
def split_helper(accum: List[List[String]], list_in2: List[String], search: String): List[List[String]] = {
val (h1, h2) = list_in2.span({x: String => x!= search})
val new_accum = accum :+ h1
if (h2.contains(search)) {
return split_helper(new_accum, h2.drop(1), search)
}
else {
return accum
}
}
return split_helper(List(), list_in, search)
}


// TEST


// split(List("a", "b", "c", "d", "c", "a"), {x: String => x != "x"})

我知道我可能会迟到,有更具体的答案,但你可以充分利用 groupBy

val ret = List(1,2,3,4).groupBy(x => x % 2 == 0)


ret: scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(1, 3), true -> List(2, 4))


ret(true)
res3: List[Int] = List(2, 4)


ret(false)
res4: List[Int] = List(1, 3)

如果您需要将条件更改为非布尔型,这使您的代码更具有未来性。