Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to split a sequence into two pieces by predicate?

Tags:

scala

By using partition method:

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

Good that partition was the thing you wanted -- there's another method that also uses a predicate to split a list in two: span.

The first one, partition will put all "true" elements in one list, and the others in the second list.

span will put all elements in one list until an element is "false" (in terms of the predicate). From that point forward, it will put the elements in the second list.

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

You might want to take a look at scalex.org - it allows you to search the scala standard library for functions by their signature. For example, type the following:

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

You would see partition.


You can also use foldLeft if you need something a little extra. I just wrote some code like this when partition didn't cut it:

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

I know I might be late for the party and there are more specific answers, but you could make good use of 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)

This makes your code a bit more future-proof if you need to change the condition into something non boolean.