从HashMap <Integer,List <Integer >>

时间:2019-06-12 17:37:02

标签: java java-8 java-stream

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

HashMap<Integer, List<Integer>>

,我必须得到一个列表,其中包含HashMap中所有列表的每个元素,并且在任何列表中出现的次数最多。因此,假设我的HashMap具有以下条目:

25, [30,30,2]

7, [2, 2, 2]

8, [8, 30]

在这种情况下,我应该以某种方式获得一个包含以下元素的列表:[2,2,2,8,8,30,30],因为每个数字的最大出现次数是:

  • 在2的情况下为3(值7)
  • 如果是8,则为1(值8)
  • 如果是30,则为2(值25)

我正在尝试使用流来这样做,并且我编写了以下代码:

map.entrySet()
            .stream()
            .map(Map.Entry::getValue)
            .collect(Collectors.toList());

这得到单个列表,但是我需要得到一个列表,其中包含任何列表中的所有元素,并具有被提及的最大次数。元素的顺序根本不重要。

请问我是否需要澄清。

谢谢您的帮助。

3 个答案:

答案 0 :(得分:2)

您可以这样:

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

测试

System.out.println(maxOccurrence(Map.of(
        25, List.of(30, 30, 2),
        7, List.of(2, 2, 2),
        8, List.of(8, 30))));

输出

[2, 2, 2, 8, 30, 30]

解释

  1. 流式传输值,即列表:

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

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

    .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.maxBy(Comparator.naturalOrder()))))
    
    {8=1, 2=3, 30=2}
    
  4. 按数字(键)排序的流:

    .entrySet().stream().sorted(Map.Entry.comparingByKey())
    
    2=3
    8=1
    30=2
    
  5. 通过出现重复每个数字:

    .flatMap(e -> LongStream.range(0, e.getValue().get()).mapToObj(x -> e.getKey()))
    
    2
    2
    2
    8
    30
    30
    
  6. 使用结果构建列表:

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

答案 1 :(得分:2)

这是使用流的快速解决方案:

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

输出

[2, 2, 2, 8, 30, 30]

答案 2 :(得分:2)

您可以使用此功能:

--

首先,您将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()); flatMap()一起使用以获取数字计数。然后,您收集所有数据,以使用出现次数的最大值(groupingBy())区分数字(Entry.getKey()。最后,您可以使用Entry.getValue()Collections.nCopies()一个具有最大出现次数的列表。

结果将是:

flatMap()