下面是一段代码,它计算数字在流中出现的次数,并返回一个Map,其中数字作为键,值作为它在流中出现的次数:
Map<Integer, Long> collect = Stream.of(1, 2, 3, 4, 4, 55555, 12) .collect(groupingBy(Function.identity(), counting()));
如何将生成的Map限制为最大的数字(或在平局的情况下的数字)?
0md85ypi1#
看看这个简单的例子:
public static void getMeNumbersWithHighestFrequence3(int[] numbers, int howMany) { Map<Integer, Long> collect = IntStream.of(numbers).boxed().collect(groupingBy(Function.identity(), TreeMap::new, counting())).descendingMap().entrySet().stream() .limit(howMany) .collect(TreeMap::new, (map, entry) -> map.put(entry.getKey(), entry.getValue()), Map::putAll); }
你也可以通过设置一个过滤器值来搜索它们,它会获取键值大于该值的所有条目,如下所示:
public static void getMeNumbersWithHighestFrequenceByFilterNumber(int[] numbers, int value) { Map<Integer, Long> collect = IntStream.of(numbers).boxed().collect(groupingBy(Function.identity(), TreeMap::new, counting())).descendingMap().headMap(value, true); }
简单用法:
public static void main(String[] args) { int[] numbers = {1, 2, 3, 4, 4, 55555, 12}; getMeNumbersWithHighestFrequence(numbers, 5); }
cedebl8k2#
我希望有人能想出一个更简单的解决办法:
List<Entry<Integer, Long>> list = List.of(3, 3, 4, 4, 5, 5, 1) .stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) .entrySet() .stream() .sorted(Map.Entry.<Integer, Long>comparingByValue().reversed()) .collect(Collectors.toList()); Map<Integer, Long> result = new HashMap<>(); Iterator<Entry<Integer, Long>> iter = list.iterator(); Entry<Integer, Long> left; Entry<Integer, Long> right = null; while (iter.hasNext()) { left = iter.next(); if (right == null) { result.put(left.getKey(), left.getValue()); } if (iter.hasNext() && (right = iter.next()).getValue().longValue() == left.getValue()) { result.put(right.getKey(), right.getValue()); } else { break; } }
所以首先把它们收集到你已经拥有的同一张Map上,然后按值排序;然后迭代该结果,并 * 仅 * 得到位于最开始并匹配其值的那些。其思想是,由于这些已经按值排序:3 = 2; 4 = 2; 5 = 2; 1 = 1-只要2被重复,我们就只需要迭代,只要不存在这样的匹配,我们就完成了(因为它们被排序,因此任何跟随和!= 2的元素只会更小)。
3 = 2; 4 = 2; 5 = 2; 1 = 1
2
!= 2
z9gpfhce3#
我假设你想得到流中出现频率最高的数字,因此你可以使用TreeMap来收集所有结果,并得到最后一个条目的列表:
TreeMap
Map<Integer, Long> collect = Stream.of(1, 2, 3, 4, 4, 55555, 12) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) .entrySet().stream() .collect(Collectors.groupingBy(Map.Entry::getValue, TreeMap::new, Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))) .lastEntry().getValue();
这将返回包含编号和频率的条目列表。在您的示例中,它将打印:
{4=2}
如果你只是想得到最大数的出现次数,你可以使用这个:
Map.Entry<Integer, Long> collect = Stream.of(1, 2, 3, 4, 4, 55555, 12) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) .entrySet().stream() .max(Map.Entry.comparingByKey()) .orElse(null);
其中打印:
55555=1
在最后一种情况下,你只有一个(最大值)返回项。你也可以使用TreeMap来获取最大值,应该会有更好的性能。
s4chpxco4#
我建议您使用StreamEx或我的库abacus-common中定义的MoreCollectors:
MoreCollectors
int result = Stream.of(1, 2, 12, 3, 4, 4, 55555, 12) .collect(MoreCollectors.maxAll(MoreCollectors.countingInt())); // map result Map<Integer, Integer> mapResult = Stream.of(1, 2, 12, 3, 4, 4, 55555, 12) .collect(maxAll(groupingBy(Function.identity(), countingInt())));
因为您可能需要:1)所有最大数字的总和,或者2)将它们Map到其他东西,或者3)...更多。不需要也不应该只为一个特定的用户情况编写这种特定的代码。(如果你想知道如何实现它,只需下载库的源代码或反编译类。它们在Apache License v2上发布)
更新。实际上,我认为如果你谈论的是数字,那么问这个问题可能是错误的,因为传统的for-loop比使用lambdas要简单和高效得多:
for-loop
int[] nums = {1, 2, 12, 3, 4, 4, 55555, 12, 55555}; int[] result = {Integer.MIN_VALUE, 0}; // [0] is the largest number if [1] (occurrence) is bigger than 0. for (int num : nums) { if (num > result[0]) { result[0] = num; result[1] = 1; } else if (num == result[0]) { result[1]++; } } System.out.println(result[0] + ": " + result[1]);
如果必须使用Stream/Lambda:
int[] result = IntStream.of(nums).collect(() -> new int[] {Integer.MIN_VALUE, 0}, (a, num) -> { if (num > a[0]) { a[0] = num; a[1] = 1; } else if (num == a[0]) { a[1]++; } }, (a1, a2) -> { if (a1[0] == a2[0]) { a1[1] += a2[1]; } else if (a1[0] < a2[0]) { a1[1] = a2[1]; } }); System.out.println(result[0] + ": " + result[1]);
4条答案
按热度按时间0md85ypi1#
看看这个简单的例子:
你也可以通过设置一个过滤器值来搜索它们,它会获取键值大于该值的所有条目,如下所示:
简单用法:
cedebl8k2#
我希望有人能想出一个更简单的解决办法:
所以首先把它们收集到你已经拥有的同一张Map上,然后按值排序;然后迭代该结果,并 * 仅 * 得到位于最开始并匹配其值的那些。
其思想是,由于这些已经按值排序:
3 = 2; 4 = 2; 5 = 2; 1 = 1
-只要2
被重复,我们就只需要迭代,只要不存在这样的匹配,我们就完成了(因为它们被排序,因此任何跟随和!= 2
的元素只会更小)。z9gpfhce3#
我假设你想得到流中出现频率最高的数字,因此你可以使用
TreeMap
来收集所有结果,并得到最后一个条目的列表:这将返回包含编号和频率的条目列表。在您的示例中,它将打印:
如果你只是想得到最大数的出现次数,你可以使用这个:
其中打印:
在最后一种情况下,你只有一个(最大值)返回项。你也可以使用
TreeMap
来获取最大值,应该会有更好的性能。s4chpxco4#
我建议您使用StreamEx或我的库abacus-common中定义的
MoreCollectors
:因为您可能需要:1)所有最大数字的总和,或者2)将它们Map到其他东西,或者3)...更多。不需要也不应该只为一个特定的用户情况编写这种特定的代码。(如果你想知道如何实现它,只需下载库的源代码或反编译类。它们在Apache License v2上发布)
更新。实际上,我认为如果你谈论的是数字,那么问这个问题可能是错误的,因为传统的
for-loop
比使用lambdas要简单和高效得多:如果必须使用Stream/Lambda: