BigO
BigO

Reputation: 15

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));
        }

Upvotes: 1

Views: 834

Answers (2)

Alexander Ivanchenko
Alexander Ivanchenko

Reputation: 29028

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.

Upvotes: 1

rizesky
rizesky

Reputation: 444

First of all what you need as your return type is actually Map.Entry, not the whole Map, since you just want an entry with highest number of occurrences.

You can try this way:

   public Map.Entry<String,Long> mostFrequentlyDuplicateLetters(List<String> letterList){
        return letterList
                .stream()
                .collect(Collectors.groupingBy(String::valueOf, Collectors.counting()))
                .entrySet()
                .stream().max(Map.Entry.comparingByValue())
                .get();
    }

Upvotes: 2

Related Questions