1. Introduction
Scala allows us to split a sequence by a predicate in several different ways. This means taking a single sequence and applying some filtering logic to it to end up with two sequences. In this tutorial we’ll explore the most common ways to do this by going through a simple example.
2. Using partition
The partition method belongs to the TraversableLike trait. We’ll use it to run a predicate against each element of a sequence and return to us two sequences. O****ne sequence contains elements that satisfy the predicate, and the other sequence contains elements that don’t satisfy it. Remember, a predicate is a function that returns a Boolean.
Let’s say we have a sequence of integers:
val intSequence: Seq[Int] = Seq(1,2,3,4,5,6)
intSequence: List(1, 2, 3, 4, 5, 6)
We’ll use partition to split this sequence into a sequence of even integers and odd integers:
val (even, odd) = intSequence.partition(_ % 2 == 0)
even: List(2, 4, 6)
odd: List(1, 3, 5)
We’ve applied a predicate that checks if the modulus of each element in the sequence equals 0. Two new sequences will be returned from this operation, which we destructure into even and odd variables.
As we can see, the result is a sequence of even numbers and a sequence of odd numbers.
3. Using span
The span method also allows us to split a sequence into two sequences. However, it works very differently from partition: span puts all elements in one sequence until an element is false, and from that point forward it will put all remaining sequence in the second list.
In this next example, we want the first half of the numbers to be in the first sequence and the second half of the numbers to be in the second sequence:
val intSequence: Seq[Int] = Seq(1,2,3,4,5,6)
val (firstHalf, secondHalf) = intSequence.span(_ <= intSequence.length / 2)
firstHalf: List(1, 2, 3)
secondHalf: List(4, 5, 6)
The remaining elements are put into the second sequence as soon as the predicate is false.
4. Using groupBy
The groupBy method works very similarly to partition in the sense that it takes a predicate function as its parameter. The difference is the output: groupBy* groups elements by key and their associated values into a *Map collection.
Let’s look at the first example with odd and even integers again:
val intSequence: Seq[Int] = Seq(1,2,3,4,5,6)
intSequence: List(1, 2, 3, 4, 5, 6)
We’ll use groupBy and supply the same predicate to check for even numbers:
val res = intSequence.groupBy(_ % 2 == 0)
res: HashMap(false -> List(1, 3, 5), true -> List(2, 4, 6))
The result is a HashMap that contains two key-value pairs: a false key with a value that contains a sequence of all the elements which don’t satisfy the predicate (odd numbers) and a true key with a value that contains a sequence of even elements.
The groupBy method is especially useful if we think we’ll need to change the condition into something that isn’t a Boolean in the future.
5. Conclusion
As demonstrated in this article, there are several different ways to split sequences in Scala, and the one we’ll choose depends on the problem we’re trying to solve:
- partition is useful when we’re simply splitting a sequence based on the result of a boolean predicate.
- span is preferable when we want to put all elements in a second sequence once an element returns false against the predicate.
- groupBy is similar to partition but allows us to future-proof our code in case the condition isn’t a Boolean in the future.