2

I am quite new to Java 8 Streams and have a question with faced me, doing homework for University. If I have 2 Intstreams with have the same amount of Integers as

IntStream one = Arrays.stream(test.matrix).flatMapToInt(Arrays::stream);
IntStream two = Arrays.stream(test2.matrix).flatMapToInt(Arrays :: stream);
IntStream difference = one - two ???

is it possible to generate a new Stream holding the elementwhise difference of the two streams? I have tried a lot like using stream.iterator(); which worked, but I am not allowed to use "normal" iterators, and should solve it with lambda expressions. Has anyone a tip on how to solve this?

  • Is this helpful? [Zipping Collections in Java](https://www.baeldung.com/java-collections-zip) Or this? [Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip)](https://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip) – Ole V.V. Dec 15 '19 at 16:23

2 Answers2

2

The operation combining two streams/lists is often called zip. Unfortunately this operation is not provided in the Java 8 standard library. You can read more about how users defined their own zip functions here: Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip)

Niko
  • 401
  • 3
  • 7
2

Overall, you'll essentially just be iterating the arrays by index. If you only iterate by elements then you cannot combine the streams in a way analogous to a zip operation. First, define what subtracting matrices looks like. For now, I'll only define same size matrices:

public static void subtract(int[] origin, int[] operand) {
    if (origin.length != operand.length) throw new IllegalArgumentException("Array lengths must match");
    //Make a new result, so as not to muck with the original array
    return IntStream.range(0, origin.length).map(i -> origin[i] - operand[i]).toArray();
}

Then generating the difference is a matter of passing in those matrices directly, and the stream is used simply as a matter of iterating both sets of elements. Thus the task could also be accomplished with a simple vanilla for loop. Nonetheless:

int[] result = subtract(one, two);

We can abstract the logic above as well to allow a more flexible set of operations:

public static int[] operate(int[] origin, int[] operand, IntBiFunction operation) {
    if (origin.length != operand.length) throw new IllegalArgumentException("Array lengths must match");
    return IntStream.range(0, origin.length)
            .forEach(i -> result[i] = operation.apply(origin[i], operand[i]))
            .toArray();
}

public static void subtract(int[] origin, int[] operand) {
    //Producing result from each index matched element
    return operate(origin, operand, (one, two) -> one - two);
}

This is where I'd see more of an advantage of using anything function api related.

If you wish to utilize a return of IntStream instead of int[], you can, but you'll run into the original issue of having to reference the arrays by index. You could really push it and supply an arbitrary amount of operations (IntBiFunction... operations), but I think you risk overcomplicating your logic.

Rogue
  • 11,105
  • 5
  • 45
  • 71