Самый частый элемент потока - PullRequest
0 голосов
/ 03 декабря 2018

Как найти наиболее часто встречающийся элемент, но если мало распространенных элементов, вернуть ноль.

Я хотел бы найти код, эквивалентный:

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

Однако потоковая версия не даетобрабатывать наиболее частые элементы с одинаковой частотой.

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

Как изменить поток выше для достижения этого?

Ответы [ 3 ]

0 голосов
/ 03 декабря 2018

Мне удалось построить объединенный Stream, но он стал длинным:

private static String mostFrequentStream3(List<String> elements) {
    return elements.stream() // part 1
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
            .entrySet().stream() // part 2
            .collect(Collectors.groupingBy(Entry::getValue))
            .entrySet().stream() // part 3
            .max(Entry.comparingByKey())
            .map(Entry::getValue)
            .filter(v -> v.size() == 1)
            .map(v -> v.get(0).getKey())
            .orElse(null);
}

Чтобы «найти наиболее частый элемент, но когда есть несколько наиболее часто встречающихся элементов, вернуть ноль»
Подсчет части 1частота каждого элемента.
Часть 2 группирует записи по частоте.
Часть 3 ищет запись с самой высокой частотой.Если у этой записи есть только один элемент («есть самые частые»), то это единственный максимум.В противном случае null возвращается.

0 голосов
/ 03 декабря 2018

Я бы никогда не использовал поток для этого, чтобы не повредить читабельности и производительности одновременно.Ради удовольствия -

private static String mostFrequentStream(List<String> elements) {
    Map<String, Long> frequencyMap = elements.stream().collect(groupingBy(Function.identity(), counting()));

    return frequencyMap.entrySet().stream()
            .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
            .limit(2).reduce((i, e) -> i.getValue().equals(e.getValue()) ? new AbstractMap.SimpleEntry<>(null, 0L) : i).get().getKey();
}
0 голосов
/ 03 декабря 2018

с использованием группировкиBy:

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

}
...