How can I count occurrences with groupBy?

JavaFunctional ProgrammingJava 8

Java Problem Overview


I want to collect the items in a stream into a map which groups equal objects together, and maps to the number of occurrences.

List<String> list = Arrays.asList("Hello", "Hello", "World");
Map<String, Long> wordToFrequency = // what goes here?

So in this case, I would like the map to consist of these entries:

Hello -> 2
World -> 1

How can I do that?

Java Solutions


Solution 1 - Java

I think you're just looking for the overload which takes another Collector to specify what to do with each group... and then Collectors.counting() to do the counting:

import java.util.*;
import java.util.stream.*;

class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("Hello");
        list.add("Hello");
        list.add("World");
        
        Map<String, Long> counted = list.stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        
        System.out.println(counted);
    }
}

Result:

{Hello=2, World=1}

(There's also the possibility of using groupingByConcurrent for more efficiency. Something to bear in mind for your real code, if it would be safe in your context.)

Solution 2 - Java

Here is example for list of Objects

Map<String, Long> requirementCountMap = requirements.stream().collect(Collectors.groupingBy(Requirement::getRequirementType, Collectors.counting()));

Solution 3 - Java

List<String> list = new ArrayList<>();

list.add("Hello");
list.add("Hello");
list.add("World");

Map<String, List<String>> collect = list.stream()
                                        .collect(Collectors.groupingBy(o -> o));
collect.entrySet()
       .forEach(e -> System.out.println(e.getKey() + " - " + e.getValue().size()));

Solution 4 - Java

Here are slightly different options to accomplish the task at hand.

using toMap:

list.stream()
    .collect(Collectors.toMap(Function.identity(), e -> 1, Math::addExact));

using Map::merge:

Map<String, Integer> accumulator = new HashMap<>();
list.forEach(s -> accumulator.merge(s, 1, Math::addExact));

Solution 5 - Java

Here is the simple solution by StreamEx:

StreamEx.of(list).groupingBy(Function.identity(), MoreCollectors.countingInt());

This has the advantage of reducing the Java stream boilerplate code: collect(Collectors.

Solution 6 - Java

If you're open to using a third-party library, you can use the Collectors2 class in Eclipse Collections to convert the List to a Bag using a Stream. A Bag is a data structure that is built for counting.

Bag<String> counted =
        list.stream().collect(Collectors2.countBy(each -> each));

Assert.assertEquals(1, counted.occurrencesOf("World"));
Assert.assertEquals(2, counted.occurrencesOf("Hello"));

System.out.println(counted.toStringOfItemToCount());

Output:

{World=1, Hello=2}

In this particular case, you can simply collect the List directly into a Bag.

Bag<String> counted = 
        list.stream().collect(Collectors2.toBag());

You can also create the Bag without using a Stream by adapting the List with the Eclipse Collections protocols.

Bag<String> counted = Lists.adapt(list).countBy(each -> each);

or in this particular case:

Bag<String> counted = Lists.adapt(list).toBag();

You could also just create the Bag directly.

Bag<String> counted = Bags.mutable.with("Hello", "Hello", "World");

A Bag<String> is like a Map<String, Integer> in that it internally keeps track of keys and their counts. But, if you ask a Map for a key it doesn't contain, it will return null. If you ask a Bag for a key it doesn't contain using occurrencesOf, it will return 0.

Note: I am a committer for Eclipse Collections.

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
QuestionMuhammad HewedyView Question on Stackoverflow
Solution 1 - JavaJon SkeetView Answer on Stackoverflow
Solution 2 - JavafjkjavaView Answer on Stackoverflow
Solution 3 - JavaSivakumarView Answer on Stackoverflow
Solution 4 - JavaOusmane D.View Answer on Stackoverflow
Solution 5 - Javauser_3380739View Answer on Stackoverflow
Solution 6 - JavaDonald RaabView Answer on Stackoverflow