Java 8, Stream - Find the count of strings that have sum of digits more than 10

Viewed 1136

I'm learning java 8 and I wrote code that finds the count of collection element, which strings contain digits with sum more than 10.

For example:

"56abc" - this string contains sum of 11 and satisfies the condition of the task

"56" - this string also contains sum of 11 and satisfies the condition of the task

"12sdf" - this string contains sum of 3 and does not satisf the condition of the task

My code works, but I think it's too large and bad. Is there a way to make it better? Thanks!

List<String> listString = Arrays.asList("83d","349d", "12");
Stream<String> s1 = listString.stream(); //get stream of string elements
Stream<IntStream> s2 = s1.map(x->x.chars()); //get stream of chars
Stream<Stream<Integer>> s3 = s2.map(IntStream::boxed); //convert IntStream to Stream<Integer> 
Stream<Stream<String>> s4 = s3.map(x->x.map(val->String.valueOf((char)val.intValue()))); //convert Stream<Integer> to Stream<String>
Stream<Stream<String>> s5 = s4.map(x->x.filter(val->val.matches("\\d+"))); //filter chars, that is not a digit
Stream<Stream<Integer>> s6 = s5.map(x->x.map(Integer::parseInt)); //convert String to Integer
Stream<Integer> s7 = s6.map(x->x.mapToInt(val->val).sum()); //find sum of digits
Stream<Integer> s8 = s7.filter(val->val>10); //filter sums that is less of 10
long count = s8.count(); //get count of elements
System.out.println("count = "+count);
2 Answers

First of all, it defeats the purpose to assign each intermediate Stream to a variable. Just chain all the method calls.

Second of all, you can achieve the same result which much fewer steps.

For each IntStream, filter out all the characters that are not between '0' and '9', map the remaining characteres to their numeric values and sum them.

List<String> listString = Arrays.asList("83d","349d", "12");
long count = listString.stream()
                       .map(x->x.chars())
                       .filter(x -> x.filter(i -> i >= '0' && i <= '9')
                                     .map(i -> i - '0')
                                     .sum() > 10)
                       .count();
System.out.println("count = " + count);

First, replace a non-digit character with an empty string. then in the filter by converting each string to IntStream and perform sum() operation you can calculate the sum of the numeric characters and at the end count the result.

listString.stream()
            .map(s -> s.replaceAll("\\D", ""))
            .filter(s -> s.chars().map(c -> Character.getNumericValue(c)).sum() > 10)
            .count();

or even better performance and more readable way suggested by Holger.

listString.stream()
           .filter(s ->s.chars()
              .filter(Character::isDigit)
              .map(Character::getNumericValue)
              .sum() > 10) 
           .count();
Related