Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to split a list in two by a condition

Short answer

partitioningBy() creates a Map with two keys: true for elements that match the condition and false for the rest:

void main() {
    var numbers = List.of(1, 2, 3, 4, 5, 6, 7);
 
    Map<Boolean, List<Integer>> parts = numbers.stream()
            .collect(Collectors.partitioningBy(n -> n % 2 == 0));
    IO.println(parts.get(true));
    IO.println(parts.get(false));
}

Output:

[2, 4, 6]
[1, 3, 5, 7]

With counting

The second argument processes each part — for example, counts the elements:

record Student(String name, int score) {}
 
void main() {
    var students = List.of(new Student("Anna", 85), new Student("Oleg", 40), new Student("Ivan", 62));
 
    var passed = students.stream()
            .collect(Collectors.partitioningBy(s -> s.score() >= 50, Collectors.counting()));
    IO.println(passed);
}

Output:

{false=1, true=2}

Both groups always exist

Unlike groupingBy(), both parts are present even when one of them is empty:

void main() {
    var numbers = List.of(2, 4, 6);
    IO.println(numbers.stream().collect(Collectors.partitioningBy(n -> n > 10)));
}

Output:

{false=[2, 4, 6], true=[]}

Common mistake

Filtering the list twice — once by the condition and once by its opposite. That is two passes and a duplicated condition that is easy to change in only one place. partitioningBy() does it all in one pass.

Functions used in this recipe

Thanks for reading!

Donate to the site — we work hard for you.