What's the purpose of partitioningBy

JavaJava 8Collectors

Java Problem Overview


For example, if I intend to partition some elements, I could do something like:

Stream.of("I", "Love", "Stack Overflow")
      .collect(Collectors.partitioningBy(s -> s.length() > 3))
      .forEach((k, v) -> System.out.println(k + " => " + v));

which outputs:

false => [I]
true => [Love, Stack Overflow]

But for me partioningBy is only a subcase of groupingBy. Although the former accepts a Predicate as parameter while the latter a Function, I just see a partition as a normal grouping function.

So the same code does exactly the same thing:

 Stream.of("I", "Love", "Stack Overflow")
       .collect(Collectors.groupingBy(s -> s.length() > 3))
       .forEach((k, v) -> System.out.println(k + " => " + v));

which also results in a Map<Boolean, List<String>>.

So is there any reason I should use partioningBy instead of groupingBy? Thanks

Java Solutions


Solution 1 - Java

partitioningBy will always return a map with two entries, one for where the predicate is true and one for where it is false. It is possible that both entries will have empty lists, but they will exist.

That's something that groupingBy will not do, since it only creates entries when they are needed.

At the extreme case, if you send an empty stream to partitioningBy you will still get two entries in the map whereas groupingBy will return an empty map.

EDIT: As mentioned below this behavior is not mentioned in the Java docs, however changing it would take away the added value partitioningBy is currently providing. For Java 9 this is already in the specs.

Solution 2 - Java

partitioningBy is slightly more efficient, using a special Map implementation optimized for when the key is just a boolean.

(It might also help to clarify what you mean; partitioningBy helps to effectively get across that there's a boolean condition being used to partition the data.)

Solution 3 - Java

partitioningBy method will return a map whose key is always a Boolean value, but in case of groupingBy method, the key can be of any Object type

//groupingBy
Map<Object, List<Person>> list2 = new HashMap<Object, List<Person>>();
list2 = list.stream().collect(Collectors.groupingBy(p->p.getAge()==22));
System.out.println("grouping by age -> " + list2);

//partitioningBy
Map<Boolean, List<Person>> list3 = new HashMap<Boolean, List<Person>>();
list3 = list.stream().collect(Collectors.partitioningBy(p->p.getAge()==22));
System.out.println("partitioning by age -> " + list2);

As you can see, the key for map in case of partitioningBy method is always a Boolean value, but in case of groupingBy method, the key is Object type

Detailed code is as follows:

    class Person {
	String name;
	int age;

	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}

	public String toString() {
		return this.name;
	}
}

public class CollectorAndCollectPrac {
	public static void main(String[] args) {
		Person p1 = new Person("Kosa", 21);
		Person p2 = new Person("Saosa", 21);
		Person p3 = new Person("Tiuosa", 22);
		Person p4 = new Person("Komani", 22);
		Person p5 = new Person("Kannin", 25);
		Person p6 = new Person("Kannin", 25);
		Person p7 = new Person("Tiuosa", 22);
		ArrayList<Person> list = new ArrayList<>();
		list.add(p1);
		list.add(p2);
		list.add(p3);
		list.add(p4);
		list.add(p5);
		list.add(p6);
		list.add(p7);

		// groupingBy
		Map<Object, List<Person>> list2 = new HashMap<Object, List<Person>>();
		list2 = list.stream().collect(Collectors.groupingBy(p -> p.getAge() == 22));
		System.out.println("grouping by age -> " + list2);

		// partitioningBy
		Map<Boolean, List<Person>> list3 = new HashMap<Boolean, List<Person>>();
		list3 = list.stream().collect(Collectors.partitioningBy(p -> p.getAge() == 22));
		System.out.println("partitioning by age -> " + list2);

	}
}

Solution 4 - Java

Another difference between groupingBy and partitioningBy is that the former takes a Function<? super T, ? extends K> and the latter a Predicate<? super T>.

When you pass a method reference or a lambda expression, such as s -> s.length() > 3, they can be used by either of these two methods (the compiler will infer the functional interface type based on the type required by the method you choose).

However, if you have a Predicate<T> instance, you can only pass it to Collectors.partitioningBy(). It won't be accepted by Collectors.groupingBy().

And similarly, if you have a Function<T,Boolean> instance, you can only pass it to Collectors.groupingBy(). It won't be accepted by Collectors.partitioningBy().

Solution 5 - Java

As denoted by the other answers, segregating a collection into two groups is useful in some scenarios. As these two partitions would always exist, it would be easier to utilize it further. In JDK, to segregate all the class files and config files, partitioningBy is used.

    private static final String SERVICES_PREFIX = "META-INF/services/";
    
    // scan the names of the entries in the JAR file
    Map<Boolean, Set<String>> map = jf.versionedStream()
            .filter(e -> !e.isDirectory())
            .map(JarEntry::getName)
            .filter(e -> (e.endsWith(".class") ^ e.startsWith(SERVICES_PREFIX)))
            .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
                                               Collectors.toSet()));

    Set<String> classFiles = map.get(Boolean.FALSE);
    Set<String> configFiles = map.get(Boolean.TRUE);

Code snippet is from jdk.internal.module.ModulePath#deriveModuleDescriptor

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2336315View Question on Stackoverflow
Solution 1 - JavaOronView Answer on Stackoverflow
Solution 2 - JavaLouis WassermanView Answer on Stackoverflow
Solution 3 - JavaVaibhav SharmaView Answer on Stackoverflow
Solution 4 - JavaEranView Answer on Stackoverflow
Solution 5 - JavaRamValliView Answer on Stackoverflow