用java 8计算字数

Dim*_*tri 7 java java-8 java-stream

我试图在java 8中实现一个字数统计程序,但我无法使它工作.该方法必须将字符串作为参数并返回a Map<String,Integer>.

当我以旧java方式进行时,everthing工作正常.但是当我尝试在java 8中执行它时,它返回一个映射,其中键是空的,具有正确的出现次数.

这是我的java 8风格的代码:

public Map<String, Integer> countJava8(String input){
       return Pattern.compile("(\\w+)").splitAsStream(input).collect(Collectors.groupingBy(e -> e.toLowerCase(), Collectors.reducing(0, e -> 1, Integer::sum)));
    }
Run Code Online (Sandbox Code Playgroud)

这是我在正常情况下使用的代码:

public Map<String, Integer> count(String input){
        Map<String, Integer> wordcount = new HashMap<>();
        Pattern compile = Pattern.compile("(\\w+)");
        Matcher matcher = compile.matcher(input);

        while(matcher.find()){
            String word = matcher.group().toLowerCase();
            if(wordcount.containsKey(word)){
                Integer count = wordcount.get(word);
                wordcount.put(word, ++count);
            } else {
                wordcount.put(word.toLowerCase(), 1);
            }
        }
        return wordcount;
 }
Run Code Online (Sandbox Code Playgroud)

主要方案:

public static void main(String[] args) {
       WordCount wordCount = new WordCount();
       Map<String, Integer> phrase = wordCount.countJava8("one fish two fish red fish blue fish");
       Map<String, Integer> count = wordCount.count("one fish two fish red fish blue fish");

        System.out.println(phrase);
        System.out.println();
        System.out.println(count);
    }
Run Code Online (Sandbox Code Playgroud)

当我运行这个程序时,我的输出:

{ =7, =1}
{red=1, blue=1, one=1, fish=4, two=1}
Run Code Online (Sandbox Code Playgroud)

我认为该方法splitAsStream会将正则表达式中的匹配元素流式传输为Stream.我怎么能纠正这个?

tob*_*s_k 9

问题似乎是你实际上是用语言进行分裂,即你是在流过一切不是单词的东西,或者是单词之间.不幸的是,似乎没有相同的流式传输实际匹配结果的方法(很难相信,但我没有发现任何;如果你知道一个,请随意评论).

相反,您可以使用非单词进行拆分,\W而不是使用\w.此外,如在评论中指出,你可以把它有点更通过可读String::toLowerCase,而不是一个拉姆达和Collectors.summingInt.

public static Map<String, Integer> countJava8(String input) {
    return Pattern.compile("\\W+")
                  .splitAsStream(input)
                  .collect(Collectors.groupingBy(String::toLowerCase,
                                                 Collectors.summingInt(s -> 1)));
}
Run Code Online (Sandbox Code Playgroud)

但恕我直言,这仍然很难理解,不仅仅是因为"反向"查找,而且很难推广到其他更复杂的模式.就个人而言,我会选择"旧学校"解决方案,也许使用新的更紧凑getOrDefault.

public static Map<String, Integer> countOldschool(String input) {
    Map<String, Integer> wordcount = new HashMap<>();
    Matcher matcher = Pattern.compile("\\w+").matcher(input);
    while (matcher.find()) {
        String word = matcher.group().toLowerCase();
        wordcount.put(word, wordcount.getOrDefault(word, 0) + 1);
    }
    return wordcount;
}
Run Code Online (Sandbox Code Playgroud)

两种情况下的结果似乎相同.

  • 对我来说,`Collectors.counting()`看起来比`Collectors.summingInt(s - > 1)`更清晰.当然,你必须使用结果类型`Map <String,Long>`然后...... (3认同)
  • 顺便说一下,使用Java 9,你可以[流过匹配](http://download.java.net/jdk9/docs/api/java/util/regex/Matcher.html#results--),所以你不要不需要反转模式,虽然结果代码稍大:`返回Pattern.compile("\\ w +").匹配器(输入).results().收集(Collectors.groupingBy(r-> r.group) ().toLowerCase(),Collectors.counting()));` (3认同)
  • 最后一句话:`getOrDefault`也是一种Java 8方法.因此,如果您想要进行旧式计数但同时使用高级Java 8 API,请使用`while(matcher.find())wordcount.merge(matcher.group().toLowerCase(),1,Integer: :总和);` (3认同)