Java 8 convert for loop and summing of values to stream/lambda?

Viewed 355

I have some String inputs that I am looping over that I am trying to convert to java 8 stream/lambdas but was having some issues. My boilerplate code looks like this:

public static int count(List<String> list) {
    String regex = "someRegexPatternHere"
    Pattern p = Pattern.compile(regex);
    int sum = 0;

    for (String val: list) {
        Matcher m = p.matcher(val);
        if (m.find()) {
            // summing logic here 
        }
    }
    return sum;
}

I was trying to do something like

list.stream()
    .filter(i -> p.matcher(i).find())
    .map(..............)
    ...

... but couldn't get the summ'ing logic down. could anyone point me in the right direction?

4 Answers

You need to apply first the matcher then filter on the find

return inputs.stream()
             .map(p::matcher)
             .filter(Matcher::find)
             .map(m -> m.group(0))
             .mapToInt(Integer::parseInt)
             .sum();

It could more clear for you to see it using lambda function but that's the same

    return inputs.stream().map(input -> p.matcher(input))
                 .filter(matcher -> matcher.find())
                 .map(m -> m.group(0))
                 .mapToInt(s -> Integer.parseInt(s)).sum();

This is a tricksy one, because of the Matcher logic. I'd write it like

list.stream()
 .map(p::matcher)
 .filter(Matcher::find)
 .mapToInt(m -> Integer.parseInt(m.group(0))
 .sum();

You are very close. Replace map() with count(), which returns a long.

long count = list.stream().filter(s -> p.matcher(s).find()).count();

As long as you refer to the Stream API feature, which origins in , rather than the specific version itself, let me introduce you a way with a newer version of Java.

Java 9+

As of the newer versions of Java, you can use method on Matcher class returning directly a Stream of results.

Returns a stream of match results for each subsequence of the input sequence that matches the pattern. The match results occur in the same order as the matching subsequences in the input sequence.

Flatmap does the thing:

int sum = list.stream()
    .map(p::matcher)
    .flatMap(Matcher::results)
    .mapToInt(mr -> Integer.parseInt(mr.group(0)))
    .sum();

... or shorter:

int sum = list.stream()
    .flatMap(string -> pattern.matcher(string).results())
    .mapToInt(mr -> Integer.parseInt(mr.group(0)))
    .sum();
Related