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

huangapple go评论143阅读模式
英文:

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

问题

Here's the translation of the provided content:

我需要在Java中使用流和Lambda表达式查找映射中的最大值。找到一个最大值不是问题,但如何找到多个呢?
示例:
一个Treemap<String, Integer> 包含元素 "e" = 2, "i" = 1, "a" = 2,
我的当前解决方案给出了 "a" = 2,但我想要 "a" = 2, "e" = 2

我的代码:

Map&lt;String, Integer&gt; frequencies = new TreeMap&lt;&gt;();
frequencies.put(&quot;e&quot;, 2);//虽然我不是这样放置值的,但这样测试一下可以
frequencies.put(&quot;i&quot;, 1);
frequencies.put(&quot;a&quot;, 2);
Optional&lt;Map.Entry&lt;String, Integer&gt;&gt; maxEntry = frequencies.entrySet().stream()
        .max(Map.Entry.comparingByValue());//frequencies是TreeMap&lt;String, Integer&gt;
//我知道这只搜索一个最大值,以下是我的另一个尝试:
try (Stream&lt;Map.Entry&lt;String, Integer&gt;&gt; stream = frequencies.entrySet().stream()) {
      stream
          .sorted(Map.Entry.comparingByValue())
          .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k, v) -&gt; k, LinkedHashMap::new));
//我不知道在这里该怎么做,我需要将结果以某种方式放入新的列表中,但它仍然只返回一个结果
    }

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

英文:

So I have to find the max value(s) in a map in java with streams and lambda. Finding one max value is not a problem, but how can I find multiple?
Example:
Treemap<String, Integer> with elements "e" = 2, "i" = 1, "a" = 2,
My current solution gives me "a" = 2, but I want "a" = 2, "e" = 2

My code:

Map&lt;String, Integer&gt; frequencies = new Treemap&lt;&gt;();
frequencies.put(&quot;e&quot;, 2);//I don&#39;t put the values in like this but it&#39;ll do to test
frequencies.put(&quot;i&quot;, 1);
frequencies.put(&quot;a&quot;, 2);
Optional&lt;Map.Entry&lt;String, Integer&gt;&gt; maxEntry = frequencies.entrySet().stream()
        .max(Map.Entry.comparingByValue());//frequencies is the TreeMap&lt;String, Integer&gt;
//I know this only searches one max value, here&#39;s my other attempt:
try (Stream&lt;Map.Entry&lt;String, Integer&gt;&gt; stream = frequencies.entrySet().stream()) {
      stream
          .sorted(Map.Entry.comparingByValue())
          .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k, v) -&gt; k, LinkedHashMap::new));
//I don&#39;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
    }

Please let me know if im doing anything wrong.

答案1

得分: 2

I will translate the code for you:

// 找到 Java 中 Map 中的最大值(值可能重复),并使用 streams 和 lambda 表达式进行处理。

// 下面是一种不使用 TreeMap 的方法,它对 Map 中的 Entry 进行频率计数。

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() : "空列表");

// 输出结果
// [a=2, e=2]

// 另一种有趣的方法是绕过初始的 map,直接创建一个 entry 流。实际上,当你创建初始的 Map 时,你已经在创建 Entry 对象,因此这里不会有额外的 Map 开销。

Stream.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() :
        "空列表");

// 输出结果与之前相同
// [a=2, e=2]

请注意,这只是代码的翻译部分,不包括解释或任何其他信息。

英文:

> So I have to find the max value(s) in a map in java with streams and lambda.

Here is one way to do it without a TreeMap. It does a frequency count of containing Entries.

Map&lt;String, Integer&gt; map = Map.of(&quot;z&quot;, -1, &quot;b&quot;, 0, &quot;r&quot;, -2,
&quot;s&quot;, 0, &quot;j&quot;, 1, &quot;a&quot;, 2, &quot;i&quot;, 1, &quot;e&quot;, 2);
Optional&lt;Entry&lt;Integer, List&lt;Entry&lt;String,Integer&gt;&gt;&gt;&gt; opt = map.entrySet()
.stream()
.collect(Collectors.groupingBy(Entry::getValue))
.entrySet().stream().max(Entry.comparingByKey());
System.out.println(opt.isPresent() ? opt.get().getValue() : &quot;Empty List&quot;);

Prints

[a=2, e=2]

And just for fun you can bypass the initial map and create a stream of entries. In reality, when you create your intitial Map you are creating Entry objects so no additional map overhead is involved here.

		
Builder&lt;Entry&lt;String, Integer&gt;&gt; entryStream = Stream.builder();
entryStream.add(Map.entry(&quot;b&quot;, 0));
entryStream.add(Map.entry(&quot;r&quot;, -2));
entryStream.add(Map.entry(&quot;s&quot;, 0));
entryStream.add(Map.entry(&quot;j&quot;, 1));
entryStream.add(Map.entry(&quot;a&quot;, 2));
entryStream.add(Map.entry(&quot;i&quot;, 1));
entryStream.add(Map.entry(&quot;e&quot;, 2));

At this point, it's the same as before except the stream is ready to invoke.

Optional&lt;Entry&lt;Integer, List&lt;Entry&lt;String, Integer&gt;&gt;&gt;&gt; opt =
entryStream.build()
.collect(Collectors
.groupingBy(Entry::getValue))
.entrySet().stream()
.max(Entry.comparingByKey());
System.out.println(opt.isPresent() ? opt.get().getValue() :
&quot;Empty List&quot;);

Prints as before

[a=2, e=2]
</details>
# 答案2
**得分**: 1
首先,找到最大频率:
```java
Optional<Integer> maxFreqOptional = frequencies.values()
.stream()
.max(Comparator.naturalOrder());

然后,您可以收集所有具有此频率的条目作为值:

Integer maxFreq = maxFreqOptional.get(); // 首先检查是否为空
List<String> mostFrequent = frequencies.entrySet()
    .stream()
    .filter(entry -> entry.getValue().equals(maxFreq))
    .map(Map.Entry<String, Integer>::getKey)
    .collect(Collectors.toList());

如果您需要任何进一步的帮助,请告诉我。

英文:

First, find the max frequency:

Optional&lt;Integer&gt; maxFreqOptional = frequencies.values()
.stream()
.max(Comparator.naturalOrder());

Then you can just collect all entries with this frequency as a value:

Integer maxFreq = maxFreqOptional.get(); // check if it&#39;s empty first
List&lt;String&gt; mostFrequent = frequencies.entrySet()
.stream()
.filter(entry -&gt; entry.getValue().equals(maxFreq))
.map(Map.Entry&lt;String, Integer&gt;::getKey)
.collect(Collectors.toList());

答案3

得分: 1

收集输入流至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();

注意:如果您的数据集很大,并且希望避免构建这个反向映射,您可能更喜欢其中一种建议的解决方案,它们两次迭代映射:一次用于找到最大频率,然后再次用于找到所有对应的条目。

英文:

You're almost there:

Collect the entry stream into a TreeMap using the value (=frequency) as key and the original key as value. Use the cascaded groupingBy therefore. Then take the entry with the largest key:

TreeMap&lt;Integer, List&lt;String&gt;&gt; map = frequencies.entrySet().stream()
.collect(Collectors.groupingBy(
Map.Entry&lt;String, Integer&gt;::getValue, TreeMap::new, Collectors.toList()
));
Map.Entry&lt;Integer, List&lt;String&gt;&gt; largest = map.lastEntry();

Note: If your data set is large and you want to avoid building up this reverse map, you may prefer one of the other suggested solutions that iterate the map twice: Once to find the largest frequence, and then again to find all corresponding entries.

答案4

得分: 1

你可以根据maxEntry的值进行筛选,以获取所有最大值的Map.Entry

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

在线演示在这里

输出结果:[a=2, e=2]

英文:

You can do filter by maxEntry's value if present to get all Map.Entry of max value

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

Online demo here

Output: [a=2, e=2]

答案5

得分: 0

以下是翻译好的部分:

"As you only need the entries that match the max value, there's no gain in grouping all the entries of the map in a reverse map. You only need to discard all entries whose value doesn't match the max value.

Here's a succinct way to do it with lambdas:

Integer max = frequencies.isEmpty() ?
Integer.MIN_VALUE :
Collections.max(frequencies.values());

List result = new ArrayList<>();
frequencies.forEach((k, v) -> { if (v.equals(max)) result.add(k); });

So, in 'max' you have the max value, while in 'result' you have the keys that match the max value. This algorithm's time complexity is 'O(n)' worst case, unlike the algorithms that group entries, which are all 'O(nlogn)'.

The streams equivalent version is more verbose:

Integer max = frequencies.values().stream()
.max(Comparator.naturalOrder())
.orElse(Integer.MIN_VALUE);

List result = frequencies.entrySet().stream()
.filter(e -> e.getValue().equals(max))
.map(Map.Entry::getKey)
.collect(Collectors.toList());"

英文:

As you only need the entries that match the max value, there's no gain in grouping all the entries of the map in a reverse map. You only need to discard all entries whose value doesn't match the max value.

Here's a succinct way to do it with lambdas:

Integer max = frequencies.isEmpty() ? 
Integer.MIN_VALUE :
Collections.max(frequencies.values());
List&lt;String&gt; result = new ArrayList&lt;&gt;();
frequencies.forEach((k, v) -&gt; { if (v.equals(max)) result.add(k); });

So, in max you have the max value, while in result you have the keys that match the max value. This algorithm's time complexity is O(n) worst case, unlike the algorithms that group entries, which are all O(nlogn).

The streams equivalent version is more verbose:

Integer max = frequencies.values().stream()
.max(Comparator.naturalOrder())
.orElse(Integer.MIN_VALUE);
List&lt;String&gt; result = frequencies.entrySet().stream()
.filter(e -&gt; e.getValue().equals(max))
.map(Map.Entry::getKey)
.collect(Collectors.toList());

huangapple
  • 本文由 发表于 2020年7月31日 20:56:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/63192272.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定