我一直在练习,其中我必须找到以下问题的解决方案:我有
HashMap<Integer, List<Integer>>
,我必须得到一个列表,其中包含HashMap中所有列表的每个元素,并且在任何列表中出现的次数最多。因此,假设我的HashMap具有以下条目:
25, [30,30,2]
7, [2, 2, 2]
8, [8, 30]
在这种情况下,我应该以某种方式获得一个包含以下元素的列表:[2,2,2,8,8,30,30],因为每个数字的最大出现次数是:
我正在尝试使用流来这样做,并且我编写了以下代码:
map.entrySet()
.stream()
.map(Map.Entry::getValue)
.collect(Collectors.toList());
这得到单个列表,但是我需要得到一个列表,其中包含任何列表中的所有元素,并具有被提及的最大次数。元素的顺序根本不重要。
请问我是否需要澄清。
谢谢您的帮助。
答案 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]
解释
流式传输值,即列表:
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()))))
{8=1, 2=3, 30=2}
按数字(键)排序的流:
.entrySet().stream().sorted(Map.Entry.comparingByKey())
2=3
8=1
30=2
通过出现重复每个数字:
.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]
答案 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()