Search code examples
javajava-streamcollectors

How to find the most frequent letters and the number of occurrences, using Stream API?


I have List with single letters inside. I need to count all duplicates and find the most frequent duplicate. The list generates randomly, so it may contain several most frequent letters.

Is it possible to create only one map inside one Stream or put the second map inside Stream? I need only one Stream chain, using the method groupingBy().

public static void mostFrequentlyDuplicateLetters(List<String> letters) {   
     Map<String, Long> collect = letterList
            .stream()
            .collect(Collectors.groupingBy(String::valueOf, Collectors.counting()))
            .entrySet()
            .stream()
            .filter(// How to find the most frequent letters and put them on a map?))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        }

Solution

  • it may contain several most frequent letters

    The solution below allows to determine all the letters from the given list that have a maximum frequency.

        public static void main(String[] args) {
            Map<String, Long> frequencies = getFrequencyMap(List.of("A", "B", "B", "C", "C", "C", "B", "D"));
            long max = getMaxFrequency(frequencies);
            System.out.println("max = " + max);
            System.out.println(mostFrequentlyDuplicateLetters(frequencies, max));
        }
    
        public static Map<String, Long> getFrequencyMap(List<String> letters) {
            return letters.stream()
                    .collect(Collectors.groupingBy(UnaryOperator.identity(), Collectors.counting()));
        }
    
        public static long getMaxFrequency(Map<String, Long> frequencies) {
            return frequencies.values().stream()
                    .mapToLong(Long::longValue)
                    .max()
                    .orElse(0);
        }
    
        public static List<String> mostFrequentlyDuplicateLetters(Map<String, Long> frequencies, 
                                                                  long frequency) {
            return frequencies.entrySet().stream()
                    .filter(entry -> entry.getValue() == frequency)
                    .map(Map.Entry::getKey)
                    .collect(Collectors.toList());
        }
    

    output (both letters B and C have frequency = 3)

    max = 3
    [B, C]
    

    Is it possible to create only one map inside one Stream

    If you want your code to be both efficient and clean the answer is NO. By trying to fuse more than one concern in one method you'll violate the first of the SOLID principles - The single responsibility principle.