How to add elements of two streams in java?

Asked

Viewed 180 times

3

Hello, I would like to make a function that sums the elements of two Streams and returns a Stream with the results, in a "functional" way without using third party libraries. For example:

BiFunction<Stream,Stream,Stream> mySoma = (s1,s2) -> ?????? ;

I know little of language and tried to look for something like a zipWith or ultimately something to iterate, like a get(), but I couldn’t find anything that worked. There’s something that does that?

(PS: I can switch to Intstream if it helps at all).

  • Sum the total of all elements of the two streams, or add element to element as if it were a new stream with the sum of each pair ?

  • I would like to sum up each pair of elements.

1 answer

3


There is no function similar to zipWith in the API of Streams of Java. It was implemented in a build of Java 8 but it was removed because, in the view of those responsible for the language, such functionality would be better provided by libraries, or even each developer could implement its own version that meets their needs.

Among the problems cited by him are:

  • is a language of other languages that does not adapt well to Java because of the absence of tuples and other types;
  • in the current version of Java, it is not possible to create a version that accepts primitive types, which may cause performance problems due to the Boxing and Unboxing variables, in addition to the need to create new SAM types;
  • difficult to parallelize;
  • multiple ways to deal with Streams of different sizes. Which should be chosen?

You can follow all the discussion about this here.

Therefore, you will have to implement a solution of your own, or use some library that has such functionality, such as Guava.

As a reference, Guava implements this method thus:

/**
 * Returns a stream in which each element is the result of passing the corresponding elementY of
 * each of {@code streamA} and {@code streamB} to {@code function}.
 *
 * <p>For example:
 *
 * <pre>{@code
 * Streams.zip(
 *   Stream.of("foo1", "foo2", "foo3"),
 *   Stream.of("bar1", "bar2"),
 *   (arg1, arg2) -> arg1 + ":" + arg2)
 * }</pre>
 *
 * <p>will return {@code Stream.of("foo1:bar1", "foo2:bar2")}.
 *
 * <p>The resulting stream will only be as long as the shorter of the two input streams; if one
 * stream is longer, its extra elements will be ignored.
 *
 * <p>Note that if you are calling {@link Stream#forEach} on the resulting stream, you might want
 * to consider using {@link #forEachPair} instead of this method.
 *
 * <p><b>Performance note:</b> The resulting stream is not <a
 * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>.
 * This may harm parallel performance.
 */
 public static <A, B, R> Stream<R> zip(
      Stream<A> streamA, Stream<B> streamB, BiFunction<? super A, ? super B, R> function) {
    checkNotNull(streamA);
    checkNotNull(streamB);
    checkNotNull(function);
    boolean isParallel = streamA.isParallel() || streamB.isParallel(); // same as Stream.concat
    Spliterator<A> splitrA = streamA.spliterator();
    Spliterator<B> splitrB = streamB.spliterator();
    int characteristics =
        splitrA.characteristics()
            & splitrB.characteristics()
            & (Spliterator.SIZED | Spliterator.ORDERED);
    Iterator<A> itrA = Spliterators.iterator(splitrA);
    Iterator<B> itrB = Spliterators.iterator(splitrB);
    return StreamSupport.stream(
            new AbstractSpliterator<R>(
                Math.min(splitrA.estimateSize(), splitrB.estimateSize()), characteristics) {
              @Override
              public boolean tryAdvance(Consumer<? super R> action) {
                if (itrA.hasNext() && itrB.hasNext()) {
                  action.accept(function.apply(itrA.next(), itrB.next()));
                  return true;
                }
                return false;
              }
            },
            isParallel)
        .onClose(streamA::close)
        .onClose(streamB::close);
}

Remark: the method checkNotNull is also part of Guava. If you want to use such an implementation without using the library, you can replace it with the method Objects.requireNonNull.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.