In data analytics, you will often need to sort collections not by the values of the elements themselves, but by their **frequency** (how many times they occur in the dataset). For example, if you are sorting user actions or search queries, you want to show the most popular items first.

In this guide, we will look at how to implement a frequency-sorting algorithm using Java 8 Streams, grouping elements into maps, and sorting them by counts.

Illustration representing leaderboards and element frequencies
Real-World Analogy: Fruit Baskets

Imagine having a pile of fruit containing 4 Apples, 3 Bananas, and 1 Pear:

  • If you sort them **alphabetically**, you get: Apple, Banana, Pear.
  • If you sort them **by popularity (frequency)**, you sort them into baskets, count them, and align them: Baskets with the most fruit go first. You end up with: Apples, then Bananas, and finally Pears.

1. Step 1: Grouping and Counting

We use Collectors.groupingBy() and Collectors.counting() to build a Map where keys are the elements and values are their occurrence counts:

Map<Integer, Long> frequencyMap = list.stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
// Input: {2, 3, 2, 2, 5, 5, 6, 5, 7, 5, 3, 1}
// Output Map: {1=1, 2=3, 3=2, 5=4, 6=1, 7=1}

2. Step 2: Sorting Map Entries by Value

Next, we stream the entry set of the map, sort it in descending order of values (counts), and process the results:

frequencyMap.entrySet().stream()
        .sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())) // Sort by count descending
        .collect(Collectors.toList());

Java Implementation

Below is the complete Java code that groups the elements, sorts the map, and expands the keys back into a sorted output list:

package io.practise.leetcode.medium;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class SortBasedOnOccurance {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(2, 3, 2, 2, 5, 5, 6, 5, 7, 5, 3, 1);
        List<Integer> output = new ArrayList<>();

        // 1. Group by element and count occurrences
        list.stream()
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                // 2. Stream entry set and sort by occurrences descending
                .entrySet().stream()
                .sorted((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()))
                .collect(Collectors.toList())
                // 3. Re-expand elements back into output list
                .forEach(entry -> {
                    for (int index = 0; index < entry.getValue(); ++index) {
                        output.add(entry.getKey());
                    }
                });

        System.out.println("Input:  " + list);
        System.out.println("Output: " + output);
        // Output: [5, 5, 5, 5, 2, 2, 2, 3, 3, 6, 7, 1]
    }
}

Conclusion

Frequency sorting is a powerful pipeline pattern. By combining Collectors.groupingBy() with stream entry comparison, you can convert complex counting-and-sorting loops into a single declarative Java statement.