使用流计数的字

时间:2016-05-27 04:37:07

标签: java java-8

我试着用Java中的Streams计算单词。这就是我的尝试:

public static int countWords(String s) {
    return s.chars().reduce((x, y) -> {
        if((char)y == ' ')
            ++x;
        return x;
    }).orElse(0);
}

countWords("asd")返回97.为什么?我认为chars会返回IntStream,其实际上由char组成。所以,我只是把它投到char。怎么了?

6 个答案:

答案 0 :(得分:8)

虽然你的问题是指计算单词,但你的代码似乎是为了计算空格而设计的。如果这是你的意图那么我会建议:

=match($A:$A, indirect("Sheet 2!A:E"),0)

这样可以避免代码中出现的许多投射错误,如果对您的域名更有意义,可以将其更改为input.chars().filter(Character::isSpaceChar).count();

但是,如果您希望计算单词,那么最简单的解决方案就是在空格上isWhitespace,然后计算非空单词:

split

答案 1 :(得分:7)

reduce运算符有不同的重载:

  • 可选reduce(BinaryOperator累加器)
  • T reduce(T identity,BinaryOperator累加器)
  • U reduce(U identity,BiFunction accumulator,BinaryOperator combiner)

如果未指定“x”的标识值,则reduce运算符将从流中获取第一个值。因此'x'最后是字母'a',整数,即97.您可能想要将代码更改为:

public static int countWords(String s) {
    return s.chars().reduce(0, (x, y) -> {
        if((char)y == ' ')
            return x + 1;
        return x;
    });
}

答案 2 :(得分:7)

我建议采用更多功能性方法:

public static long countWords(String s) {
    return Arrays
            .stream(s.split(" "))
            .filter(w -> !w.isEmpty())
            .count();
}

答案 3 :(得分:2)

使用reduce时,你正在处理元组:x是第一个字符或累加器,y是secone char变量。

此处,x始终指向a,其中ASCII值为97

Pattern#splitAsStream(CharSequence)

您可能希望在您的情况下使用此方法,它可以正确完成工作,并且您可以编写更易于维护的代码。

public static int countWords(String s) {
    return (int)Pattern.compile(" ")
                       .splitAsStream(s)
                       .count();
}

答案 4 :(得分:1)

计算空间:查看短跑运动员的反应;表现:看到对erkfel的回应的评论;正确应用reduce:请参阅Andrew Williamson的回复。

现在我将它们全部合并到以下内容中:

public static int countWords(String s)
{
    int c = s.chars().reduce(0, (x, y) ->
        {
            if(x < 0)
            {
                if(Character.isWhitespace(y))
                {
                    x = -x;
                }
            }
            else
            {
                if(!Character.isWhitespace(y))
                {
                    x = -(x + 1);
                }
            }
            return x;
        });
    return c < 0 ? -c : c;
}

这以非常有效的方式计算真实的单词,而不是空白。内部隐藏着一个小技巧:我使用负值来表示“在一个单词中”的状态,使用正值来表示“在空白序列中”。我选择它不需要携带额外的布尔值,从而使我们免于编写实现IntBinaryOperation的显式类(另外,这使得lamda表达式保持无状态,仍然在reduction文章中讨论的并行化是不可能的此运算符关联...))。

编辑:正如霍尔格指出的那样(我认为是正确的),这种用法是滥用实际上的实际意图(有几个相似的值,并将它们减少到一个仍然与原始值相同;示例:汇总或乘以数值列表,结果仍为数字 - 或连接字符串列表,结果仍为字符串)。

所以简单地迭代字符串似乎更合适:

public static int countWords(String s)
{
    int count = 0;
    boolean isWord = false;
    for(int i = 0; i < s.length(); i++)
    {
        if(isWord)
        {
            if(Character.isWhitespace(s.charAt(i)))
            {
                isWord = false;
            }
        }
        else
        {
            if(!Character.isWhitespace(s.charAt(i)))
            {
                ++count;
                isWord = true; 
            }
        }
    return count;
}

我个人喜欢紧凑型变体,虽然不太容易理解:

public static int countWords(String s)
{
    int count = 0;
    boolean isWord = false;
    for(int i = 0; i < s.length(); i++)
    {
        boolean isChange = isWord == Character.isWhitespace(s.charAt(i));
        isWord ^= isChange;
        count += isWord & isChange ? 1 : 0;
    }
    return count;
}

答案 5 :(得分:1)

流?怎么样:

int wordCount = str.trim().split("\\s+").length();

如果你拼命必须使用溪流(不推荐):

int wordCount = Arrays.stream(str.trim().split("\\s+")).count();