Mar*_*tin 2 java functional-programming java-8 java-stream
我想在 java 中的字符串列表中计算单个单词的出现次数。看似这个任务很简单,但我遇到了一个问题,单词以大写字母开头或包含,或.在单词末尾。我的方法看起来像:
public static Long countWordOccurence(List<String> wordList, String word) {
return wordList.stream()
.filter(s -> word.contains(s))
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.values()
.stream()
.findFirst()
.orElse((long) -1);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在正常情况下工作正常,但问题发生在像字符串末尾的昏迷Test,或以大写字母开头的字符串这样的角落情况下。
我正在拆分我的字符串列表,如:
Arrays.asList(TEXT_TO_PARSE.split(" "));
Run Code Online (Sandbox Code Playgroud)
如果可能的话,我会很感激避免额外的依赖,但如果有必要,我不会鄙视。
我将不胜感激关于如何在流中修复我的过滤器子句以正确计算字符串的建议。
您的代码存在几个基本问题。
.filter(s -> word.contains(s))执行子字符串搜索。与您的问题标题相反,它不会忽略大小写。尽管如此,仍然可以有不同内容的字符串通过过滤器
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))根据字符串的实际内容创建组。所以当多个不同的字符串通过前面的过滤器时,可能存在多个组
.values().stream().findFirst():由于groupingBy创建了一个未指定排序的地图,这将选择一个任意组。除此之外,这是一种非常低效的方式来询问count()
.orElse((long) -1)该值-1是计数的一个非常奇怪的回退,因为当没有匹配项时,最自然的答案将是“零”。
所以一个直接的解决方案是
public static long countWordOccurence(List<String> wordList, String word) {
return Collections.frequency(wordList, word);
}
Run Code Online (Sandbox Code Playgroud)
用于计算区分大小写的匹配或
public static long countWordOccurence(List<String> wordList, String word) {
return wordList.stream().filter(word::equalsIgnoreCase).count();
}
Run Code Online (Sandbox Code Playgroud)
用于计数不区分大小写。
但无论如何,这是一个xy问题。
当您想要计算字符串中某个单词的出现次数时,在执行实际搜索之前,无需将字符串拆分为单词并将数组转换为列表(顺便说一下,您可以直接对数组进行流式处理)。
您可以使用
public static long countWordOccurence(String sentence, String word) {
if(!word.codePoints().allMatch(Character::isLetter))
throw new IllegalArgumentException(word+" is not a word");
Pattern p = Pattern.compile("\\b"+word+"\\b");
return p.matcher(sentence).results().count();
}
Run Code Online (Sandbox Code Playgroud)
对于区分大小写的匹配项和
public static long countWordOccurence(String sentence, String word) {
if(!word.codePoints().allMatch(Character::isLetter))
throw new IllegalArgumentException(word+" is not a word");
Pattern p = Pattern.compile("\\b"+word+"\\b", Pattern.CASE_INSENSITIVE);
return p.matcher(sentence).results().count();
}
Run Code Online (Sandbox Code Playgroud)
对于不区分大小写的匹配。该\b模式表示单词边界,只有当搜索字符串实际上是一个单词时才有意义。因此,上述方法对此进行了预测试,这也确保该单词不包含可能被误解为正则表达式模式的字符。
该results()方法是在 Java 9 中引入的。这个答案显示了在 Java 8 下创建这样一个流的解决方案,但是,对于像计算出现次数这样的简单任务,替代方法是不要在这里使用流:
public static long countWordOccurence(String sentence, String word) {
if(!word.codePoints().allMatch(Character::isLetter))
throw new IllegalArgumentException(word+" is not a word");
Pattern p = Pattern.compile("\\b"+word+"\\b", Pattern.CASE_INSENSITIVE);
int count = 0;
for(Matcher m = p.matcher(sentence); m.find(); count++) {}
return count;
}
Run Code Online (Sandbox Code Playgroud)