I’m comparing two lists based on the following conditions:
If list1 has higher value,
+1
to the first element in the result.If list2 has higher value,
+1
to the second element in the result.If values are the same, skip it.
I have implemented this solution in Java 7
int min = a.size() > b.size() ? b.size() : a.size(); List<Integer> result = Arrays.asList(0, 0); for(int i =0; i < min; i++) { if(a.get(i) > b.get(i)) result.set(0, result.get(0) + 1); else if(a.get(i) < b.get(i)) result.set(1, result.get(1) + 1); } return result;
How could I do the same with Java 8 streams?
I came up with two streams and merging the results of both. Because I am not sure how to do both the conditions in single streams.
Advertisement
Answer
Using range()
method of the IntStream
we can create a stream of indices that are valid for these lists.
To filter out indices for which values are not equal, we can apply filter()
operation.
Accumulating the result in a list comprised of two elements will require a bit more effort. For that we can use collect(supplier,accumulator,combiner)
:
- supplier – a function that returns a new mutable container. Here we need to provide a list that should hold the results of reduction;
- accumulator – is a function defines the logic on how to add stream elements into the container;
- combiner – a function that defines how to merge the two containers with partial results obtained while executing the stream in parallel.
List<Integer> a = List.of(1, 2, 5); List<Integer> b = List.of(1, 2, 8); List<Integer> result = IntStream.range(0, Math.min(a.size(), b.size())) .filter(i -> a.get(i) != b.get(i)) // filter out non-equal elements .collect( () -> Arrays.asList(0, 0), // supplier - provides a container which contain the results of reduction (list, i) -> { // combiner - difines the logic on the container should be updated if (a.get(i) > b.get(i)) list.set(0, list.get(0) + 1); else list.set(1, list.get(1) + 1); }, (left, right) -> { // accumulator - provides the logic for merging the two containers while executing in parallel left.set(0, left.get(0) + right.get(0)); left.set(1, left.get(1) + right.get(1)); } ); System.out.println(result);
Output:
[0, 1]
In case you doubt where it’s a correct way to approach this problem with streams, have a look at the API documentation, paragraph Mutable reduction.
And even if after getting familiar with the reference above, you might think that it can be done without collect()
. For instance, why don’t we simply apply filter().forEach()
to make the code leaner? Then have a look at another part of the API documentation, which is dedicated to Side-effects.