-1

For example, I want something like this:

n = {1, 2, 3, 4, 5}
m = {1, 2, 3, 4, 5}
x = Arrays.stream(n);
y = Arrays.stream(n);
IntStream.multiply(x,y) // int stream now containing squares

I want to avoid doing something like:

Intstream.range(0, x.count())
.map(i-> {
    z= biFunction.apply(
        x.findFirst().get(),
        y.findFirst().get()
    );
    x.skip(1);
    y.skip(1);
    return z;
})

(creating an int-stream, solely for the indices).

user2340612
  • 10,053
  • 4
  • 41
  • 66
Tobiq
  • 2,489
  • 19
  • 38
  • 2
    Unfortunately, I don't think this is possible. Java streams aren't applicable to every computational situation. You'll have to use something like the provided example (which I personally don't think looks too bad). – cbryant02 Jun 05 '19 at 01:44
  • 1
    I'd rather simply use arrays – Tobiq Jun 05 '19 at 01:47
  • All up to you. The stream solution is definitely more elegant but direct array access is more performant. – cbryant02 Jun 05 '19 at 01:59
  • What is your expected output for this example? – Jacob G. Jun 05 '19 at 02:08
  • @Tobiq Even if you have such a `BiFunction` such as `Math::multiplyExact` to calculate the product of two numbers. The indices of the numbers would have to be specified somehow. – Naman Jun 05 '19 at 02:14
  • @Naman, no. `double[] merge(double[] x, double[] y, BiFunction func) { double[] result = new double[x.length]; for (int i = 0; i < x.length; i++) result[i] = func.apply(x[i], y[i]); return result; }` – Tobiq Jun 05 '19 at 02:34
  • `x[i], y[i]` is what I meant by specifying the indices. – Naman Jun 05 '19 at 04:47
  • Why do you think “creating an int-stream, solely for the indices” is worse than creating *two streams* for the arrays? And regarding [this comment](https://stackoverflow.com/questions/56453202/is-it-possible-to-apply-a-bifunction-across-2-streams#comment99499921_56453202), what is that `i` you are looping over, if not the index @Naman talked about? – Holger Jun 05 '19 at 10:49
  • @Holger Because the creation of the streams for the array is done once, *for this example*. Where as the creation of the index-stream would occur on every iteration. I'm reusing and remapping the streams. It's less convenient to do this with arrays, you're constantly creating a new one, for each map - and manually implementing the map /functions yourself. I could've used `IntStream.generate` to skip the use of the *example* arrays. – Tobiq Jun 05 '19 at 12:43
  • Streams can only be used once. You always have to recreate the streams, so the numbers do not change, with the working solution, you have to create one `IntStream` and chain one `map` operation, with your proposed operation, you have to create two array streams, followed by the combining operation. – Holger Jun 05 '19 at 12:52
  • @Holger Look at the editted question, without using arrays, the implementations horrible – Tobiq Jun 05 '19 at 12:52
  • Your edited example makes no sense. As said, streams can be used only once, so `x` is unusable after `x.count()` and `y` would be unusable after the first `y.skip(i).findFirst().get()` operation, but this code would already throw before that point. – Holger Jun 05 '19 at 12:55
  • I don't get your point. There's no good way to apply a bifunction over two streams - without interaction between arrays / iterators – Tobiq Jun 05 '19 at 12:56
  • @Holger Yes, you said that. I never claimed that it was a solution. But you're not adding anything, i.e. a solution without arrays / iterators. – Tobiq Jun 05 '19 at 13:04
  • I never claimed that there was a solution without array or iterators. I only said, `Intstream.range(0, n.length).map(i-> n[i] * m[i]) …` is a viable solution for processing two arrays and anything, you’re proposing, is more complicated than that. And your edits make it worse and worse. Just understand that streams can only be used once, regardless of how you reorder the broken multiple uses of the source streams. – Holger Jun 05 '19 at 13:07
  • So just to make it clear; you are asking about a general solution for combining two `Stream` instances, e.g. when the sources are not known to be arrays? – Holger Jun 05 '19 at 13:16
  • @Holger Yes indeed – Tobiq Jun 05 '19 at 13:55

1 Answers1

1

It’s possible, but I have a hard time imagining a situation where it would be worthwhile. We construct an iterator over the products, convert it to a spliterator and then to a stream.

    int[] n = {1, 2, 3, 4, 5};
    int[] m = {1, 2, 3, 4, 5};
    IntStream x = Arrays.stream(n);
    IntStream y = Arrays.stream(m);
    PrimitiveIterator.OfInt nIt = x.iterator();
    PrimitiveIterator.OfInt mIt = y.iterator();

    Iterator<Integer> prodIterator = new Iterator<>() {

        @Override
        public boolean hasNext() {
            return nIt.hasNext() && mIt.hasNext();
        }

        @Override
        public Integer next() {
            // Apply your BiFunction here
            return nIt.next() * mIt.nextInt();
        }
    };

    Iterable<Integer> prodIterable = () -> prodIterator;

    Stream<Integer> productStream = StreamSupport.stream(prodIterable.spliterator(), false);

    productStream.forEach(System.out::println);

Output:

1
4
9
16
25

If you want an IntStream, I trust you to unbox the Stream<Integer> yourself.

Notice that if the original streams have got different numbers of elements in them, extra elements in the longer stream will be tacitly ignored, which is probably not what you want. Please think of something better.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161