I have a Stream<Set<Integer>> intSetStream.
I can do this on it...
Set<Integer> theSetWithTheMax = intSetStream.max( (x,y)->{ return Integer.compare( x.size(), y.size() ); } ).get( );
...and I get a hold of the Set<Integer> that has the highest number of Integer elements in it.
That's great. But what I really need to know is, is it the 1st Set in that Stream that's the max? Or is it the 10th Set in the Stream? Or the ith Set? Which one of them has the most elements in it?
So my question is: Is there some way — using the Stream API — that I can determine "It was the ith Set in the Stream of Sets that returned the largest value of them all, for the Set.size( ) call"?
The best solution I can think of, is to iterate over the Stream<Set<Integer>> (using intSetStream.iterator()) and do a hand-rolled max( ) calculation. But I'm hoping to learn a more Stream-y way to go about it; if there is such a thing.
You can do this with a custom collector:
int posOfMax = stream.mapToInt(Set::size)
.collect(() -> new int[] { 0, -1, -1 },
(a,i) -> { int pos = a[0]++; if(i>a[2]) { a[1] = pos; a[2] = i; } },
(a1,a2) -> {
if(a2[2] > a1[2]) { a1[1] = a1[0]+a2[1]; a1[2] = a2[2]; }
a1[0] += a2[0];
})[1];
This is the most lightweight solution. Its logic becomes clearer when we use a dedicated class instead of an array:
int posOfMax = stream.mapToInt(Set::size)
.collect(() -> new Object() { int size = 0, pos = -1, max = -1; },
(o,i) -> { int pos = o.size++; if(i>o.max) { o.pos = pos; o.max = i; } },
(a,b) -> {
if(b.max > a.max) { a.pos = a.size+b.pos; a.max = b.max; }
a.size += b.size;
}).pos;
The state object holds the size, which is simply the number of elements encountered so far, the last encountered max value and its position which we update to the previous value of the size if the current element is bigger than the max value. That’s what the accumulator function (the second argument to collect) does.
In order to support arbitrary evaluation orders, i.e. parallel stream, we have to provide a combiner function (the last argument to collect). It merges the state of two partial evaluation into the first state. If the second state’s max value is bigger, we update the first’s max value and the position, whereas we have to add the first state’s size to the second’s position to reflect the fact that both are partial results. Further, we have to update the size to the sum of both sizes.
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