最频繁的元素流

时间:2018-12-03 15:13:05

标签: java java-stream frequency

如何查找最频繁的元素,但是当最频繁的元素很少时,返回null。

我想找到与以下代码等效的代码:

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 :(得分:3)

使用分组依据:

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

}

答案 1 :(得分:2)

我设法构建了一个串联的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);
}

要“查找最频繁的元素,但是当最频繁的元素很少时,返回null”
第1部分计算了每个元素的频率。
第2部分按频率对条目进行分组。
第3部分查找频率最高的条目。如果该条目仅包含一个元素(“最常出现的很少”),则它是一个且唯一的最大值。否则返回null

答案 2 :(得分:0)

我永远不会使用流来避免同时损害可读性和性能。为了好玩-

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