Java-Stream – Grouping and Sorting based on aggregate count in Java 11

Java-Stream – Grouping and Sorting based on aggregate count in Java 11

Problem Description:

I have a Stream of custom objects as a parameter to a method. And obviously I can consume the Stream only once.

My object has a String attribute called category.

public class MyType {
    private String category;
    
    // other properties, getters, etc.
}

I need a sorted list of categories List<String>.

First, I need to sort the data based on the number of occurrences of each category. If the number of occurrences is the same, then sort such categories lexicographically.

Basically, I need something like this

java8 stream grouping and sorting on aggregate sum

but I don’t have the luxury of consuming the stream more than once. So I don’t know how to address this problem.

Here’s an example:

Input:

{
    object1 :{category:"category1"},
    object2 :{category:"categoryB"},
    object3 :{category:"categoryA"},
    object4 :{category:"category1"},
    object5 :{category:"categoryB"},
    object6 :{category:"category1"},
    object7 :{category:"categoryA"}
}

Output:

List = {category1, categoryA, categoryB}

Solution – 1

You can generate a Map of frequencies for each category of type Map<String,Long> (count by category).

Then create a stream over its entries and sort them (by Value, i.e. by count, and Key, i.e. lexicographically), extract the category from each entry and store the result into a list.

Assuming that you have the following domain type:

public class MyType {
    private String category;
    
    // getters
}

Method generating a sorted list of categories might be implemented like this:

public static List<String> getSortedCategories(Stream<MyType> stream) {
    
    return stream.collect(Collectors.groupingBy(
            MyType::getCategory,
            Collectors.counting()
        ))
        .entrySet().stream()
        .sorted(
            Map.Entry.<String, Long>comparingByValue()
                .thenComparing(Map.Entry.comparingByKey())
        )
        .map(Map.Entry::getKey)
        .toList();
}
Rate this post
We use cookies in order to give you the best possible experience on our website. By continuing to use this site, you agree to our use of cookies.
Accept
Reject