使用 java 中的流和 lambda 在(树)图中查找所有最大值
Finding all max values in (tree)map with streams and lambda in java
所以我必须在 java 的地图中使用流和 lambda 找到最大值。找到一个最大值不是问题,但如何找到多个呢?
例子:
包含元素“e”= 2、“i”= 1、“a”= 2 的 Treemap,
我目前的解决方案给了我“a”= 2,但我想要“a”= 2,“e”= 2
我的代码:
Map<String, Integer> frequencies = new Treemap<>();
frequencies.put("e", 2);//I don't put the values in like this but it'll do to test
frequencies.put("i", 1);
frequencies.put("a", 2);
Optional<Map.Entry<String, Integer>> maxEntry = frequencies.entrySet().stream()
.max(Map.Entry.comparingByValue());//frequencies is the TreeMap<String, Integer>
//I know this only searches one max value, here's my other attempt:
try (Stream<Map.Entry<String, Integer>> stream = frequencies.entrySet().stream()) {
stream
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k, v) -> k, LinkedHashMap::new));
//I don't know what to do here, I somehow would have to get the result into a new list, but it still only returns one result
}
如果我做错了什么,请告诉我。
首先,找到最大频率:
Optional<Integer> maxFreqOptional = frequencies.values()
.stream()
.max(Comparator.naturalOrder());
那么你可以只收集所有具有这个频率的条目作为一个值:
Integer maxFreq = maxFreqOptional.get(); // check if it's empty first
List<String> mostFrequent = frequencies.entrySet()
.stream()
.filter(entry -> entry.getValue().equals(maxFreq))
.map(Map.Entry<String, Integer>::getKey)
.collect(Collectors.toList());
你快完成了:
使用值(=频率)作为键,使用原始键作为值,将入口流收集到 TreeMap
中。因此使用级联groupingBy
。然后取key最大的条目:
TreeMap<Integer, List<String>> map = frequencies.entrySet().stream()
.collect(Collectors.groupingBy(
Map.Entry<String, Integer>::getValue, TreeMap::new, Collectors.toList()
));
Map.Entry<Integer, List<String>> largest = map.lastEntry();
注意:如果你的数据集很大并且你想避免建立这个反向映射,你可能更喜欢其他建议的迭代映射两次的解决方案之一:一次找到最大的频率,然后再次查找所有对应的条目。
您可以按 maxEntry
的值进行过滤(如果存在)以获得所有 Map.Entry
的最大值
List<Map.Entry<String, Integer>> res = frequencies.entrySet().stream()
.filter(e -> e.getValue().equals(maxEntry.get().getValue()))
.collect(Collectors.toList());
在线演示here
输出:[a=2, e=2]
So I have to find the max value(s) in a map in java with streams and lambda.
这是一种不用 TreeMap 的方法。它对包含条目的频率进行计数。
Map<String, Integer> map = Map.of("z", -1, "b", 0, "r", -2,
"s", 0, "j", 1, "a", 2, "i", 1, "e", 2);
Optional<Entry<Integer, List<Entry<String,Integer>>>> opt = map.entrySet()
.stream()
.collect(Collectors.groupingBy(Entry::getValue))
.entrySet().stream().max(Entry.comparingByKey());
System.out.println(opt.isPresent() ? opt.get().getValue() : "Empty List");
版画
[a=2, e=2]
为了好玩,您可以绕过初始地图并创建条目流。实际上,当您创建初始 Map 时,您正在创建 Entry 对象,因此此处不涉及额外的 map 开销。
Builder<Entry<String, Integer>> entryStream = Stream.builder();
entryStream.add(Map.entry("b", 0));
entryStream.add(Map.entry("r", -2));
entryStream.add(Map.entry("s", 0));
entryStream.add(Map.entry("j", 1));
entryStream.add(Map.entry("a", 2));
entryStream.add(Map.entry("i", 1));
entryStream.add(Map.entry("e", 2));
此时,除了流已准备好调用外,与之前相同。
Optional<Entry<Integer, List<Entry<String, Integer>>>> opt =
entryStream.build()
.collect(Collectors
.groupingBy(Entry::getValue))
.entrySet().stream()
.max(Entry.comparingByKey());
System.out.println(opt.isPresent() ? opt.get().getValue() :
"Empty List");
像以前一样打印
[a=2, e=2]
由于您只需要匹配最大值的条目,因此将映射的所有条目分组到反向映射中没有任何好处。您只需要丢弃所有值与最大值不匹配的条目。
这是使用 lambda 表达式的简洁方法:
Integer max = frequencies.isEmpty() ?
Integer.MIN_VALUE :
Collections.max(frequencies.values());
List<String> result = new ArrayList<>();
frequencies.forEach((k, v) -> { if (v.equals(max)) result.add(k); });
所以,在 max
中你有最大值,而在 result
中你有匹配最大值的键。该算法的时间复杂度是 O(n)
最坏情况,不像分组条目的算法,它们都是 O(nlogn)
.
流等效版本更详细:
Integer max = frequencies.values().stream()
.max(Comparator.naturalOrder())
.orElse(Integer.MIN_VALUE);
List<String> result = frequencies.entrySet().stream()
.filter(e -> e.getValue().equals(max))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
所以我必须在 java 的地图中使用流和 lambda 找到最大值。找到一个最大值不是问题,但如何找到多个呢?
例子:
包含元素“e”= 2、“i”= 1、“a”= 2 的 Treemap
我的代码:
Map<String, Integer> frequencies = new Treemap<>();
frequencies.put("e", 2);//I don't put the values in like this but it'll do to test
frequencies.put("i", 1);
frequencies.put("a", 2);
Optional<Map.Entry<String, Integer>> maxEntry = frequencies.entrySet().stream()
.max(Map.Entry.comparingByValue());//frequencies is the TreeMap<String, Integer>
//I know this only searches one max value, here's my other attempt:
try (Stream<Map.Entry<String, Integer>> stream = frequencies.entrySet().stream()) {
stream
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k, v) -> k, LinkedHashMap::new));
//I don't know what to do here, I somehow would have to get the result into a new list, but it still only returns one result
}
如果我做错了什么,请告诉我。
首先,找到最大频率:
Optional<Integer> maxFreqOptional = frequencies.values()
.stream()
.max(Comparator.naturalOrder());
那么你可以只收集所有具有这个频率的条目作为一个值:
Integer maxFreq = maxFreqOptional.get(); // check if it's empty first
List<String> mostFrequent = frequencies.entrySet()
.stream()
.filter(entry -> entry.getValue().equals(maxFreq))
.map(Map.Entry<String, Integer>::getKey)
.collect(Collectors.toList());
你快完成了:
使用值(=频率)作为键,使用原始键作为值,将入口流收集到 TreeMap
中。因此使用级联groupingBy
。然后取key最大的条目:
TreeMap<Integer, List<String>> map = frequencies.entrySet().stream()
.collect(Collectors.groupingBy(
Map.Entry<String, Integer>::getValue, TreeMap::new, Collectors.toList()
));
Map.Entry<Integer, List<String>> largest = map.lastEntry();
注意:如果你的数据集很大并且你想避免建立这个反向映射,你可能更喜欢其他建议的迭代映射两次的解决方案之一:一次找到最大的频率,然后再次查找所有对应的条目。
您可以按 maxEntry
的值进行过滤(如果存在)以获得所有 Map.Entry
的最大值
List<Map.Entry<String, Integer>> res = frequencies.entrySet().stream()
.filter(e -> e.getValue().equals(maxEntry.get().getValue()))
.collect(Collectors.toList());
在线演示here
输出:[a=2, e=2]
So I have to find the max value(s) in a map in java with streams and lambda.
这是一种不用 TreeMap 的方法。它对包含条目的频率进行计数。
Map<String, Integer> map = Map.of("z", -1, "b", 0, "r", -2,
"s", 0, "j", 1, "a", 2, "i", 1, "e", 2);
Optional<Entry<Integer, List<Entry<String,Integer>>>> opt = map.entrySet()
.stream()
.collect(Collectors.groupingBy(Entry::getValue))
.entrySet().stream().max(Entry.comparingByKey());
System.out.println(opt.isPresent() ? opt.get().getValue() : "Empty List");
版画
[a=2, e=2]
为了好玩,您可以绕过初始地图并创建条目流。实际上,当您创建初始 Map 时,您正在创建 Entry 对象,因此此处不涉及额外的 map 开销。
Builder<Entry<String, Integer>> entryStream = Stream.builder();
entryStream.add(Map.entry("b", 0));
entryStream.add(Map.entry("r", -2));
entryStream.add(Map.entry("s", 0));
entryStream.add(Map.entry("j", 1));
entryStream.add(Map.entry("a", 2));
entryStream.add(Map.entry("i", 1));
entryStream.add(Map.entry("e", 2));
此时,除了流已准备好调用外,与之前相同。
Optional<Entry<Integer, List<Entry<String, Integer>>>> opt =
entryStream.build()
.collect(Collectors
.groupingBy(Entry::getValue))
.entrySet().stream()
.max(Entry.comparingByKey());
System.out.println(opt.isPresent() ? opt.get().getValue() :
"Empty List");
像以前一样打印
[a=2, e=2]
由于您只需要匹配最大值的条目,因此将映射的所有条目分组到反向映射中没有任何好处。您只需要丢弃所有值与最大值不匹配的条目。
这是使用 lambda 表达式的简洁方法:
Integer max = frequencies.isEmpty() ?
Integer.MIN_VALUE :
Collections.max(frequencies.values());
List<String> result = new ArrayList<>();
frequencies.forEach((k, v) -> { if (v.equals(max)) result.add(k); });
所以,在 max
中你有最大值,而在 result
中你有匹配最大值的键。该算法的时间复杂度是 O(n)
最坏情况,不像分组条目的算法,它们都是 O(nlogn)
.
流等效版本更详细:
Integer max = frequencies.values().stream()
.max(Comparator.naturalOrder())
.orElse(Integer.MIN_VALUE);
List<String> result = frequencies.entrySet().stream()
.filter(e -> e.getValue().equals(max))
.map(Map.Entry::getKey)
.collect(Collectors.toList());