繁体   English   中英

Java Stream Collect-如何推断类型?

[英]Java Stream collect - how to deduce type?

我得到了一个单词Stream<String> words ,一个Stream<String> words ,以及一个(someString, someInt) Pair<String,Integer>类,该类实现了一个简单的元组(someString, someInt)具有两个名为getFirst,setFirst,getSecond的元素的getter和setter方法, setSecond。

现在,我应该将流中的每个单词装在Pair (word, 1) ,然后使用收集器以某种方式使整个事情告诉我每个单词在文本中出现的频率。 现在,我查找了一个收集器,该收集器应该让我做我想做的事情,并将其作为.collect(...)传递给流。
但是整个过程看起来是如此复杂,并且在该主题中浮动的类型推断,推论和通配符并没有使它变得更容易,所以我现在不知道它是什么,这是我创建的。

我试过从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())
      )
   ));

尝试使用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();

它使用提供的内容从您的流中创建地图:

  • keyMapper-产生键的映射函数
  • valueMapper-产生值的映射函数
  • mergeFunction-合并函数,用于解决与同一键关联的值之间的冲突

因此,它通过字符串值将Pairs分组到一个映射,然后您只需调用.values()即可获得Pairs的集合

最简单(虽然不一定最有效)的解决方案是将其分组到一个地图,然后将条目转换成对:

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

我同意,进入收集器世界一开始可能会有些令人恐惧,尤其是在需要处理通用类型参数的情况下。

有和没有流,有很多方法可以解决您的问题。

带流:

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)这意味着,我们发现在第一次的字,所以我们正在创建新Pair例如该单词的计数为1 )。

第三个参数是一个合并函数,当第一个参数返回已经属于该映射的键时,将用于合并值。 由于地图对于同一个键不能有多个条目,因此我们需要一种方法来地图中该键已存在的值与第二个参数产生的新值合并 在这种情况下, o代表旧值, n代表新值。 我合并值的方式是对单词的计数求和,然后在Pair实例中设置与旧值相对应的新计数。 有没有必要建立一个新的实例Pair用字和新的计数,因为它安全通过突变的旧实例累积计数Pair

没有流:

Map<String, Pair<String, Integer>> map = new HashMap<>();
words.forEach(word -> map.merge(
    word, 
    new Pair<>(word, 1),
    (o, n) -> {
        o.setSecond(o.getSecond() + n.getSecond()); 
        return o;
    }));

Collection<Pair<String, Integer>> result = map.values();

它使用Map.merge并具有与先前代码相似的语义。

暂无
暂无

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

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