我获得了一个单词流Stream<String> words
和一个类Pair<String,Integer>
,它为(someString, someInt)
实现了一个简单的元组,其中包含两个元素的getter和setter方法,名为getFirst,setFirst, getSecond,setSecond。
我现在应该将流的每个单词装入一对(word, 1)
,然后使用收集器以某种方式使整个事情告诉我每个单词在文本中的频率。现在我已经找到了一个应该让我按照自己的意愿行事的收藏家,然后将它作为.collect(...)传递给流媒体。
但整个事情看起来如此复杂,在这个主题中浮动的类型推断,演绎和通配符并没有使它变得更容易,所以我现在没有线索,只是它是什么我是&#39;创造了。
我试过从API中推断它,并尝试了我能想到的所有内容,但似乎没有一个匹配:
words
.map(x -> new Pair<String,Integer>(x,1))
.collect(Collectors.groupingBy(
x -> x.getFirst(),
Collectors.reducing(
(a,b) -> new Pair<String,Integer>(a.getFirst(), a.getSecond() + b.getSecond())
)
));
答案 0 :(得分:2)
尝试使用Collectors.toMap
:
Collection<Pair<String, Integer>> values = words.collect(Collectors.toMap(
Function.identity(),
s -> new Pair<>(s, 1),
(a, b) -> {a.setSecond(a.getSecond() + b.getSecond()); return a;}
)).values();
它使用提供的内容从您的信息流创建地图:
因此,它将您的Pairs按字符串值分组到地图,然后您只需调用.values()
即可获得Pairs集合
答案 1 :(得分:1)
最简单(但不一定最有效)的解决方案是分组到地图,然后将条目转换为对:
List<Pair<String, Integer>> pairs = words
.collect(Collectors.groupingBy(x -> x, Collectors.summingInt(x -> 1)))
.entrySet()
.stream()
.map(e -> new Pair(e.getKey(), e.getValue()))
.collect(Collectors.toList());
答案 2 :(得分:1)
我同意进入收藏家的世界在开始时可能有点可怕,特别是如果你需要处理泛型类型参数。
有许多方法可以解决您的问题,无论是否有流。
使用流:
Map<String, Pair<String, Integer>> map = words.stream()
.collect(Collectors.toMap(
word -> word,
word -> new Pair<>(word, 1),
(o, n) -> {
o.setSecond(o.getSecond() + n.getSecond());
return o;
}));
Collection<Pair<String, Integer>> result = map.values();
Collectors.toMap
的工作原理是将流的每个元素转换为键(这是第一个参数word -> word
,这意味着我们将该单词保留为原样,这样它就成了地图的关键),并通过将流的每个元素转换为值(这是第二个参数word -> new Pair<>(word, 1)
,这意味着我们第一次找到了这个词,所以我们创建了一个新的{{1}该单词的实例,计数为Pair
)。
第三个参数是一个合并函数,用于在第一个参数返回已经属于地图的键时合并值。由于映射不能为同一个键创建多个条目,因此我们需要一种方法来合并该键的映射中已有的值,以及第二个参数生成的新值。在这种情况下,1
代表旧值,o
代表新值。合并值的方法是将单词的计数相加,并在n
实例中设置与旧值对应的新计数。没有必要使用单词和新计数创建Pair
的新实例,因为通过变更 Pair
的旧实例来累积计数是安全的。
没有溪流:
Pair
这使用Map.merge
并且具有与前一代码类似的语义。