Is it possible to express the following logic more succinctly using Java 8 stream constructs?
public static Set<Pair> findSummingPairsLookAhead(int[] data, int sum){
Set<Pair> collected = new HashSet<>();
Set<Integer> lookaheads = new HashSet<>();
for(int i = 0; i < data.length; i++) {
int elem = data[i];
if(lookaheads.contains(elem)) {
collected.add(new Pair(elem, sum - elem));
}
lookaheads.add(sum - elem);
}
return collected;
}
Something to the effect of Arrays.stream(data).forEach(...).
An algorithm that involves mutating a state during iteration is not well-suited for streams. However, it is often possible to rethink an algorithm in terms of bulk operations that do not explicitly mutate any intermediate state.
In your case, the task is to collect a set of Pair(x, sum - x) where sum - x appears before x in the list. So, we can first build a map of numbers to the index of their first occurrence in the list and then use that map to filter the list and build the set of pairs:
Map<Integer, Integer> firstIdx = IntStream.range(0, data.length)
.boxed()
.collect(toMap(i -> data[i], i -> i, (a, b) -> a));
Set<Pair> result = IntStream.range(0, data.length)
.filter(i -> firstIdx.contains(sum - data[i]))
.filter(i -> firstIdx.get(sum - data[i]) < i)
.mapToObj(i -> new Pair(data[i], sum - data[i]))
.collect(toSet());
You can shorten the two filters by either using && or getOrDefault if you find that clearer.
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