Java 从HashMap获取每个数字的最大出现次数<;整数,列表<;整数>&燃气轮机;

Java 从HashMap获取每个数字的最大出现次数<;整数,列表<;整数>&燃气轮机;,java,java-8,java-stream,Java,Java 8,Java Stream,我一直在做一个练习,在这个练习中,我必须找到以下问题的解决方案:我有一个 HashMap<Integer, List<Integer>> 在本例中,我应该以某种方式获得一个包含以下元素的列表:[2,2,2,8,30,30],因为每个数字的最大出现次数为: 对于2,它是3(在值7中) 如果为8,则为1(值为8) 如果为30,则为2(值为25) 我正在尝试使用streams来实现这一点,我已经编写了以下代码: map.entrySet() .st

我一直在做一个练习,在这个练习中,我必须找到以下问题的解决方案:我有一个

HashMap<Integer, List<Integer>>
在本例中,我应该以某种方式获得一个包含以下元素的列表:[2,2,2,8,30,30],因为每个数字的最大出现次数为:

  • 对于2,它是3(在值7中)
  • 如果为8,则为1(值为8)
  • 如果为30,则为2(值为25)
我正在尝试使用streams来实现这一点,我已经编写了以下代码:

map.entrySet()
            .stream()
            .map(Map.Entry::getValue)
            .collect(Collectors.toList());
这会得到单独的列表,但我需要的是得到一个列表,其中包含任何列表中的所有元素,并且有最多的被提及次数。元素的顺序根本不重要

如果你需要澄清,请问我

提前感谢您的帮助。

您可以这样做:

static List<Integer> maxOccurrence(Map<Integer, List<Integer>> input) {
    return input.values().stream()
        .flatMap(list -> list.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())).entrySet().stream())
        .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.maxBy(Comparator.naturalOrder()))))
        .entrySet().stream().sorted(Map.Entry.comparingByKey())
        .flatMap(e -> LongStream.range(0, e.getValue().get()).mapToObj(x -> e.getKey()))
        .collect(Collectors.toList());
}
输出

[2,2,2,8,30,30]
解释

  • 流式传输值,即列表:

    input.values().stream()
    
    [8,30]
    [2, 2, 2]
    [30, 30, 2]
    
  • 计算每个列表中每个值的出现次数:

    .flatMap(list -> list.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())).entrySet().stream())
    
    8=1
    30=1
    2=3
    30=2
    2=1
    
  • 对于每个数字,选择最高的出现次数:

    .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.maxBy(Comparator.naturalOrder()))))
    
    .flatMap(e -> LongStream.range(0, e.getValue().get()).mapToObj(x -> e.getKey()))
    
    {8=1,2=3,30=2}
    
  • 按编号(键)排序的流:

    2=3
    8=1
    30=2
    
  • 按引用重复每个数字:

    .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.maxBy(Comparator.naturalOrder()))))
    
    .flatMap(e -> LongStream.range(0, e.getValue().get()).mapToObj(x -> e.getKey()))
    
    2
    2.
    2.
    8.
    30
    30
    
  • 创建一个包含结果的列表:

    .collect(Collectors.toList())
    
    [2,2,2,8,30,30]
    

  • 以下是使用streams的快速解决方案:

    public static void main(String[] args) {
        Map<Integer, List<Integer>> map = new HashMap<>();
        map.put(25, Arrays.asList(30, 30, 2));
        map.put(7, Arrays.asList(2, 2, 2));
        map.put(8, Arrays.asList(8, 30));
    
        List<Integer> result = map.values().stream() // Stream<List<Integer>>
                .map(e -> e.stream().collect(Collectors.groupingBy(p -> p, Collectors.counting()))) // Stream<Map<Integer,Long>>
                .flatMap(m -> m.entrySet().stream()) // Stream<Entry<Integer,Long>>
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Long::max)) // Map<Integer,Long>
                .entrySet().stream() // Stream<Entry<Integer,Long>>
                .flatMap(e -> repeatElement(e.getKey(), e.getValue())) // Stream<Integer>
                .collect(Collectors.toList());
    
        System.out.println(result);
    }
    
    private static Stream<Integer> repeatElement(Integer key, Long value) {
        return Stream.generate(() -> key)
                .limit(value);
    }
    
    您只需使用以下功能:

    List<Integer> result = map.values().stream()
            .flatMap(list -> list.stream().collect(Collectors.groupingBy(i -> i, Collectors.summingInt(i -> 1))).entrySet().stream())
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Integer::max)).entrySet().stream()
            .flatMap(e -> Collections.nCopies(e.getValue(), e.getKey()).stream())
            .collect(Collectors.toList());
    

    我怀疑这件事不可能一蹴而就。你必须使用流吗?似乎循环会使任务更容易。不,这不是必须的;我只是想实践流,不知何故我觉得它必须使用它们来解决;只要使用。我想你可以使用带有自定义收集器的流,只要你练习如何使用它们。你可以使用更简单的
    .collector.toMap,而不是
    .collector(collector.groupby(Map.Entry::getKey,collector.mapping)(Map.Entry::getValue,collector.maxBy(Comparator.naturalOrder()))
    (Map.Entry::getKey,Map.Entry::getValue,Long::max))
    ,这也消除了以后调用
    get()
    (在
    可选
    )的需要。当您使用
    .collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue,Long::max,TreeMap::new))
    时,您不需要后续的
    (Map.Entry.comparingByKey())
    step.@Holger True。既然其他两个答案都是这样的,我就不做了。当然,我也可以使用
    groupingBy
    的版本,它需要一个地图供应商,就像
    toMap
    有这样一个超负荷,但是最后的排序很容易,也很快,而其他两个答案并没有做到这一点,所以我想调整键更好,以突出显示需要排序。
    [2, 2, 2, 8, 30, 30]
    
    List<Integer> result = map.values().stream()
            .flatMap(list -> list.stream().collect(Collectors.groupingBy(i -> i, Collectors.summingInt(i -> 1))).entrySet().stream())
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Integer::max)).entrySet().stream()
            .flatMap(e -> Collections.nCopies(e.getValue(), e.getKey()).stream())
            .collect(Collectors.toList());
    
    [2, 2, 2, 8, 30, 30]