Search code examples
javajava-streamfrequency

Most frequent element stream


How to find most frequent element, but when there are few most frequent element return null.

I would like to find code equivalent of:

public static void main(String[] args) {
    System.out.println("Should return A -> " + mostFrequent(Arrays.asList("A", "A", "B")));
    System.out.println("Should null as element in list have same frequency -> "
            + mostFrequent(Arrays.asList("A", "B")));
}

private static String mostFrequent(List<String> elements) {
    Map<String, Long> ordered = new TreeMap<>();
    for (String e : elements) {
        if (!ordered.containsKey(e)) {
            ordered.put(e, 0L);
        }
        Long tmp = ordered.get(e);
        ordered.put(e, ++tmp);
    }

    String mostFrequent = null;
    long i = 0;
    Iterator<Map.Entry<String, Long>> it = ordered.entrySet().iterator();
    while (it.hasNext() && i < 2) {
        Map.Entry<String, Long> pair = it.next();
        if (i == 0) {
            mostFrequent = pair.getKey();
        } else {
            if (ordered.get(mostFrequent) == ordered.get(pair.getKey())) {
                return null;
            }
        }
        i++;
    }

    return mostFrequent;
}

However stream version does not handle most frequent elements with the same frequency.

private static String mostFrequentStream(List<String> elements) {
    return elements.stream()
            .reduce(BinaryOperator.maxBy(
                    Comparator.comparingInt(o -> Collections.frequency(elements, o))))
            .orElse(null);
}

How to modify stream above to achieve it?


Solution

  • using groupingBy:

    String mostFrequentStream(List<String> elements) {
        Map<String, Long> temp = elements.stream()
                .collect(Collectors.groupingBy(a -> a, Collectors.counting()));
    
    
        return new HashSet<>(temp.values()).size() < temp.size() ? 
              null : temp.entrySet()
                         .stream()
                         .max(Map.Entry.comparingByValue())
                         .map(Map.Entry::getKey).get();
    
    }