While doing a project I wrote this line, basically it decided whether or not to merge the current node based on how many children there are.
int succNodes = Arrays.stream(children).mapToInt(PRQuadNode::count).sum();
if (succNodes <= bucketingParam) { /* do something */ }
The problem is that succNodes
will often be significantly larger than bucketingParam
. And there's no point to continue counting if I have already found a large enough sum. What would be the best way to enable the stream to stop early, if I knew I was going to fail the check succNodes <= bucketingParam?
Note: In this case children is always of size 4.
Note 2: PRQuadNode::count is a recursive method, it is not tail recursive.
Actually, Java 9 comes with the takeWhile
method, which is a short-circuiting operation of the stream, returning the longest prefix of elements matching the given predicate.
Because the predicate depends on the sum of the previous elements, a wrapper has to be used in order to store the intermediate result. In the example below, I use the AtomicInteger
class:
AtomicInteger sum = new AtomicInteger();
Arrays.asList(2, 3, 5, 7, 11, 13, 17).stream()
.takeWhile(i -> sum.addAndGet(i) < 15)
.forEach(System.out::println);
Returns:
2
3
5
You cannot short-circuit the stream pipeline with the use of streams alone.
one workaround (with the use of side-effects) would be:
int[] c = new int[1];
boolean r = Arrays.stream(children).noneMatch(e -> (c[0] = c[0] + e.count()) > bucketingParam);
if (r) { /* do something */ }
This accomplishes the task but unfortunately, is not threadsafe (doubt you're ever going to run this in parallel anyway as your source will always have 4 elements).
An imperative approach would be:
int succNodes = 0;
boolean result = true;
for (PRQuadNode p : children) {
if (succNodes > bucketingParam) {
result = false;
break;
}
succNodes += p.count();
}
if (result) { /* do something */ }
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