我想将流中的项目收集到一个映射中,该映射将相等的对象分组在一起,并映射到出现的次数。
List<String> list = Arrays.asList("Hello", "Hello", "World");
Map<String, Long> wordToFrequency = // what goes here?
所以在这种情况下,我希望地图包含以下条目:
Hello -> 2
World -> 1
我该怎么做?
我认为你只是在寻找 overload ,它需要另一个
Collector
来指定如何处理每个组......然后 Collectors.counting()
进行计数:
import java.util.*;
import java.util.stream.*;
class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Hello");
list.add("World");
Map<String, Long> counted = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
System.out.println(counted);
}
}
结果:
{Hello=2, World=1}
(还可以使用
groupingByConcurrent
来提高效率。如果在您的上下文中安全的话,您的实际代码需要记住一些事情。)
这是对象列表的示例
Map<String, Long> requirementCountMap = requirements.stream().collect(Collectors.groupingBy(Requirement::getRequirementType, Collectors.counting()));
这里有一些略有不同的选项来完成手头的任务。
使用
toMap
:
list.stream()
.collect(Collectors.toMap(Function.identity(), e -> 1, Math::addExact));
使用
Map::merge
:
Map<String, Integer> accumulator = new HashMap<>();
list.forEach(s -> accumulator.merge(s, 1, Math::addExact));
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Hello");
list.add("World");
Map<String, List<String>> collect = list.stream()
.collect(Collectors.groupingBy(o -> o));
collect.entrySet()
.forEach(e -> System.out.println(e.getKey() + " - " + e.getValue().size()));
这是 StreamEx 的简单解决方案:
StreamEx.of(list).groupingBy(Function.identity(), MoreCollectors.countingInt());
这具有减少 Java 流样板代码的优点:
collect(Collectors.
如果您愿意使用第三方库,则可以使用
Eclipse Collections中的
Collectors2
类,使用 List
将 Bag
转换为 Stream
。 Bag
是一种数据结构,是为计数而构建的。
Bag<String> counted =
list.stream().collect(Collectors2.countBy(each -> each));
Assert.assertEquals(1, counted.occurrencesOf("World"));
Assert.assertEquals(2, counted.occurrencesOf("Hello"));
System.out.println(counted.toStringOfItemToCount());
输出:
{World=1, Hello=2}
在这种特殊情况下,您可以简单地将
collect
直接转换为 List
。Bag
您还可以通过使用 Eclipse Collections 协议调整
Bag<String> counted =
list.stream().collect(Collectors2.toBag());
,在不使用
Bag
的情况下创建 Stream
。List
或者在这个特殊情况下:
Bag<String> counted = Lists.adapt(list).countBy(each -> each);
您也可以直接创建 Bag。
Bag<String> counted = Lists.adapt(list).toBag();
A
Bag<String> counted = Bags.mutable.with("Hello", "Hello", "World");
就像
Bag<String>
一样,它在内部跟踪键及其计数。 但是,如果您向 Map<String, Integer>
询问它不包含的密钥,它将返回 Map
。 如果您使用 null
向 Bag
询问它不包含的密钥,它将返回 0。注意:
我是 Eclipse Collections 的提交者。