In an effort to learn Java, I'm working on a solution to the Project Euler's problem 23 where I need to find the sum of all the positive integers which cannot be written as the sum of two abundant numbers. My solution uses Java 8 streams. I will not spoil it by posting the actual answer here, but I will discuss my strategy to get to the solution.
First, I create a list of abundant numbers using an IntStream:
List<Integer> abundants = IntStream.range(1, EULER23_MAX)
.filter(i -> Util.sumOfDivisors(i) > i)
.boxed()
.collect(Collectors.toList());
Then, based on the list, I create a set of sums of 2 abundants numbers lower than the max:
private Set<Integer> calcSumsOfTwoAbundants(List<Integer> abundants) {
Set<Integer> iset = new HashSet<>();
Integer[] arr = abundants.toArray(new Integer[abundants.size()]);
for (int i = 0; i < arr.length - 2; i++) {
for (int j = i; j < arr.length - 1; j++) {
int sum = arr[i] + arr[j];
if (sum <= EULER23_MAX) {
iset.add(sum);
}
}
}
return iset;
}
Lastly, I generate another stream that filters out all numbers lower than the max that are present in the set of sums of two abundants, and I sum that to get to the result.
result = IntStream.range(1, EULER23_MAX)
.filter(x -> !sumsOfTwoAbundants.contains(x))
.sum();
My questions is this: How can I encode the logic in calcSumsOfTwoAbundants to
use a streams fluent syntax instead of the nested for loops? I have tried a
couple of different things, but I keep getting to the "stream has already been
closed" error message or to the entirely wrong result. I also understand the
the nested for loops are perhaps faster than using streams, but this is
purely an intellectual exercise ... this is what I have right now:
// wrong results
private Set<Integer> calcSumsOfTwoAbundantsAlt(List<Integer> abundants) {
return abundants.stream()
.filter(i -> abundants.stream()
.anyMatch(j -> (i + j) <= EULER23_MAX))
.collect(Collectors.toSet());
}
The most direct equivalent would be replacing each for loop with IntStream.range and nesting them with flatMap:
Set<Integer> iset = IntStream.range(0, arr.length - 2)
.flatMap(i -> IntStream.range(i, arr.length - 1)
.map(j -> arr[i] + arr[j]).filter(s -> s <= EULER23_MAX))
.boxed().collect(Collectors.toSet());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With