繁体   English   中英

在 java 中使用流和 lambda 查找(树)图中的所有最大值

[英]Finding all max values in (tree)map with streams and lambda in java

所以我必须在 java 和 lambda 中找到 map 中的最大值。 找到一个最大值不是问题,但我怎样才能找到多个? 示例:Treemap<String, Integer> 元素为“e”=2,“i”=1,“a”=2,我当前的解决方案给我“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
    }

如果我做错了什么,请告诉我。

所以我必须在 java 和 lambda 中找到 map 中的最大值。

这是没有 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 并创建一个 stream 条目。 实际上,当您创建初始 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));

此时,除了 stream 已准备好调用之外,它与之前相同。

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]

首先,找到最大频率:

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

您快到了:

使用值(=频率)作为键,原始键作为值,将条目 stream 收集到TreeMap中。 因此使用级联groupingBy 然后取最大键的条目:

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

注意:如果您的数据集很大,并且您希望避免构建此反向 map,您可能更喜欢其他建议的解决方案之一,即迭代 map 两次:一次找到最大频率,然后再次找到所有对应条目。

如果存在,您可以按maxEntry的值进行过滤以获取所有Map.Entry的最大值

List<Map.Entry<String, Integer>> res = frequencies.entrySet().stream()
                                 .filter(e -> e.getValue().equals(maxEntry.get().getValue()))
                                 .collect(Collectors.toList());

在线演示在这里

Output: [a=2, e=2]

由于您只需要匹配最大值的条目,因此将 map 的所有条目分组到反向 map 中没有任何好处。 您只需要丢弃其值与最大值不匹配的所有条目。

这是使用 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());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM