All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.landawn.abacus.util.stream.LongStream Maven / Gradle / Ivy

Go to download

A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.

There is a newer version: 5.3.16
Show newest version
/*
 * Copyright (C) 2016, 2017, 2018, 2019 HaiYang Li
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.landawn.abacus.util.stream;

import java.math.BigInteger;
import java.nio.LongBuffer;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.PrimitiveIterator;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.annotation.IntermediateOp;
import com.landawn.abacus.annotation.LazyEvaluation;
import com.landawn.abacus.annotation.ParallelSupported;
import com.landawn.abacus.annotation.SequentialOnly;
import com.landawn.abacus.annotation.TerminalOp;
import com.landawn.abacus.util.Array;
import com.landawn.abacus.util.AsyncExecutor;
import com.landawn.abacus.util.ClassUtil;
import com.landawn.abacus.util.ContinuableFuture;
import com.landawn.abacus.util.Fn.FnL;
import com.landawn.abacus.util.IndexedLong;
import com.landawn.abacus.util.LongIterator;
import com.landawn.abacus.util.LongList;
import com.landawn.abacus.util.LongSummaryStatistics;
import com.landawn.abacus.util.MergeResult;
import com.landawn.abacus.util.MutableInt;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.Pair;
import com.landawn.abacus.util.Percentage;
import com.landawn.abacus.util.Throwables;
import com.landawn.abacus.util.u.Holder;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalLong;
import com.landawn.abacus.util.function.BiConsumer;
import com.landawn.abacus.util.function.BinaryOperator;
import com.landawn.abacus.util.function.BooleanSupplier;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.LongBiFunction;
import com.landawn.abacus.util.function.LongBiPredicate;
import com.landawn.abacus.util.function.LongBinaryOperator;
import com.landawn.abacus.util.function.LongConsumer;
import com.landawn.abacus.util.function.LongFunction;
import com.landawn.abacus.util.function.LongMapMultiConsumer;
import com.landawn.abacus.util.function.LongNFunction;
import com.landawn.abacus.util.function.LongPredicate;
import com.landawn.abacus.util.function.LongSupplier;
import com.landawn.abacus.util.function.LongTernaryOperator;
import com.landawn.abacus.util.function.LongToDoubleFunction;
import com.landawn.abacus.util.function.LongToFloatFunction;
import com.landawn.abacus.util.function.LongToIntFunction;
import com.landawn.abacus.util.function.LongTriPredicate;
import com.landawn.abacus.util.function.LongUnaryOperator;
import com.landawn.abacus.util.function.ObjLongConsumer;
import com.landawn.abacus.util.function.Supplier;
import com.landawn.abacus.util.function.ToLongFunction;

/**
 * The Stream will be automatically closed after execution(A terminal method is executed/triggered).
 *
 * @see BaseStream
 * @see Stream
 */
@com.landawn.abacus.annotation.Immutable
@LazyEvaluation
public abstract class LongStream extends StreamBase {

    static final Random RAND = new SecureRandom();

    LongStream(final boolean sorted, final Collection closeHandlers) {
        super(sorted, null, closeHandlers);
    }

    @Override
    public LongStream skipUntil(final LongPredicate predicate) {
        assertNotClosed();

        return dropWhile(t -> !predicate.test(t));
    }

    @ParallelSupported
    @IntermediateOp
    public abstract LongStream map(LongUnaryOperator mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract IntStream mapToInt(LongToIntFunction mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract FloatStream mapToFloat(LongToFloatFunction mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract DoubleStream mapToDouble(LongToDoubleFunction mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract  Stream mapToObj(LongFunction mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract LongStream flatMap(LongFunction mapper);

    // public abstract LongStream flattMap(LongFunction mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract LongStream flattMap(LongFunction mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract IntStream flatMapToInt(LongFunction mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract FloatStream flatMapToFloat(LongFunction mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract DoubleStream flatMapToDouble(LongFunction mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract  Stream flatMapToObj(LongFunction> mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract  Stream flattMapToObj(LongFunction> mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract  Stream flatMappToObj(LongFunction mapper);

    @ParallelSupported
    @IntermediateOp
    public abstract LongStream mapMulti(LongMapMultiConsumer mapper);

    /**
     * Note: copied from StreamEx: https://github.com/amaembo/streamex
     *
     * @param 
     * @param mapper
     * @return
     */
    @Beta
    @ParallelSupported
    @IntermediateOp
    public abstract LongStream mapPartial(LongFunction mapper);

    /**
     * Note: copied from StreamEx: https://github.com/amaembo/streamex
     *
     * @param 
     * @param mapper
     * @return
     */
    @Beta
    @ParallelSupported
    @IntermediateOp
    public abstract LongStream mapPartialJdk(LongFunction mapper);

    /**
     * Note: copied from StreamEx: https://github.com/amaembo/streamex
     *
     * 
* * Returns a stream consisting of results of applying the given function to * the ranges created from the source elements. * This is a quasi-intermediate * partial reduction operation. * * @param sameRange a non-interfering, stateless predicate to apply to * the leftmost and next elements which returns true for elements * which belong to the same range. * @param mapper a non-interfering, stateless function to apply to the * range borders and produce the resulting element. If value was * not merged to the interval, then mapper will receive the same * value twice, otherwise it will receive the leftmost and the * rightmost values which were merged to the range. * @return * @see #collapse(LongBiPredicate, LongBinaryOperator) * @see Stream#rangeMap(BiPredicate, BiFunction) */ @SequentialOnly @IntermediateOp public abstract LongStream rangeMap(final LongBiPredicate sameRange, final LongBinaryOperator mapper); /** * Note: copied from StreamEx: https://github.com/amaembo/streamex * *
* * Returns a stream consisting of results of applying the given function to * the ranges created from the source elements. * This is a quasi-intermediate * partial reduction operation. * * @param sameRange a non-interfering, stateless predicate to apply to * the leftmost and next elements which returns true for elements * which belong to the same range. * @param mapper a non-interfering, stateless function to apply to the * range borders and produce the resulting element. If value was * not merged to the interval, then mapper will receive the same * value twice, otherwise it will receive the leftmost and the * rightmost values which were merged to the range. * @return * @see Stream#rangeMap(BiPredicate, BiFunction) */ @SequentialOnly @IntermediateOp public abstract Stream rangeMapToObj(final LongBiPredicate sameRange, final LongBiFunction mapper); /** * Merge series of adjacent elements which satisfy the given predicate using * the merger function and return a new stream. * *
* This method only runs sequentially, even in parallel stream. * * @param collapsible * @return */ @SequentialOnly @IntermediateOp public abstract Stream collapse(final LongBiPredicate collapsible); /** * Merge series of adjacent elements which satisfy the given predicate using * the merger function and return a new stream. * *
* This method only runs sequentially, even in parallel stream. * * @param collapsible * @param mergeFunction * @return */ @SequentialOnly @IntermediateOp public abstract LongStream collapse(final LongBiPredicate collapsible, final LongBinaryOperator mergeFunction); /** * * @param collapsible test the current element with the first element and previous element in the series. The first parameter is the first element of this series, the second parameter is the previous element and the third parameter is the current element. * @param mergeFunction * @return */ @SequentialOnly @IntermediateOp public abstract LongStream collapse(final LongTriPredicate collapsible, final LongBinaryOperator mergeFunction); /** * Returns a {@code Stream} produced by iterative application of a accumulation function * to an initial element {@code init} and next element of the current stream. * Produces a {@code Stream} consisting of {@code init}, {@code acc(init, value1)}, * {@code acc(acc(init, value1), value2)}, etc. * *

This is an intermediate operation. * *

Example: *

     * accumulator: (a, b) -> a + b
     * stream: [1, 2, 3, 4, 5]
     * result: [1, 3, 6, 10, 15]
     * 
* *
* This method only runs sequentially, even in parallel stream. * * @param accumulator the accumulation function * @return */ @SequentialOnly @IntermediateOp public abstract LongStream scan(final LongBinaryOperator accumulator); /** * Returns a {@code Stream} produced by iterative application of a accumulation function * to an initial element {@code init} and next element of the current stream. * Produces a {@code Stream} consisting of {@code init}, {@code acc(init, value1)}, * {@code acc(acc(init, value1), value2)}, etc. * *

This is an intermediate operation. * *

Example: *

     * init:10
     * accumulator: (a, b) -> a + b
     * stream: [1, 2, 3, 4, 5]
     * result: [11, 13, 16, 20, 25]
     * 
* *
* This method only runs sequentially, even in parallel stream. * * @param init the initial value. it's only used once by accumulator to calculate the fist element in the returned stream. * It will be ignored if this stream is empty and won't be the first element of the returned stream. * * @param accumulator the accumulation function * @return */ @SequentialOnly @IntermediateOp public abstract LongStream scan(final long init, final LongBinaryOperator accumulator); /** * * @param init * @param accumulator * @param initIncluded * @return */ @SequentialOnly @IntermediateOp public abstract LongStream scan(final long init, final LongBinaryOperator accumulator, final boolean initIncluded); @SequentialOnly @IntermediateOp public abstract LongStream prepend(final long... a); @SequentialOnly @IntermediateOp public abstract LongStream append(final long... a); @SequentialOnly @IntermediateOp public abstract LongStream appendIfEmpty(final long... a); /** *
* This method only runs sequentially, even in parallel stream. * * @param n * @return */ @SequentialOnly @IntermediateOp public abstract LongStream top(int n); /** *
* This method only runs sequentially, even in parallel stream. * * @param n * @return */ @SequentialOnly @IntermediateOp public abstract LongStream top(final int n, Comparator comparator); @SequentialOnly @TerminalOp public abstract LongList toLongList(); /** * * @param keyMapper * @param valueMapper * @return * @see Collectors#toMap(Throwables.Function, Throwables.Function) */ @ParallelSupported @TerminalOp public abstract Map toMap(Throwables.LongFunction keyMapper, Throwables.LongFunction valueMapper) throws E, E2; /** * * @param keyMapper * @param valueMapper * @param mapFactory * @return * @see Collectors#toMap(Throwables.Function, Throwables.Function, Supplier) */ @ParallelSupported @TerminalOp public abstract , E extends Exception, E2 extends Exception> M toMap(Throwables.LongFunction keyMapper, Throwables.LongFunction valueMapper, Supplier mapFactory) throws E, E2; /** * * @param keyMapper * @param valueMapper * @param mergeFunction * @return * @see Collectors#toMap(Throwables.Function, Throwables.Function, BinaryOperator) */ @ParallelSupported @TerminalOp public abstract Map toMap(Throwables.LongFunction keyMapper, Throwables.LongFunction valueMapper, BinaryOperator mergeFunction) throws E, E2; /** * * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return * @see Collectors#toMap(Throwables.Function, Throwables.Function, BinaryOperator, Supplier) */ @ParallelSupported @TerminalOp public abstract , E extends Exception, E2 extends Exception> M toMap(Throwables.LongFunction keyMapper, Throwables.LongFunction valueMapper, BinaryOperator mergeFunction, Supplier mapFactory) throws E, E2; /** * * @param keyMapper * @param downstream * @return * @see Collectors#groupingBy(Throwables.Function, Collector) */ @ParallelSupported @TerminalOp public abstract Map groupTo(Throwables.LongFunction keyMapper, final Collector downstream) throws E; /** * * @param keyMapper * @param downstream * @param mapFactory * @return * @see Collectors#groupingBy(Throwables.Function, Collector, Supplier) */ @ParallelSupported @TerminalOp public abstract , E extends Exception> M groupTo(Throwables.LongFunction keyMapper, final Collector downstream, final Supplier mapFactory) throws E; @ParallelSupported @TerminalOp public abstract long reduce(long identity, LongBinaryOperator op); @ParallelSupported @TerminalOp public abstract OptionalLong reduce(LongBinaryOperator op); /** * * @param * @param supplier * @param accumulator * @param combiner * @return * @see Stream#collect(Supplier, BiConsumer, BiConsumer) */ @ParallelSupported @TerminalOp public abstract R collect(Supplier supplier, ObjLongConsumer accumulator, BiConsumer combiner); /** * * @param supplier * @param accumulator * @return * @see Stream#collect(Supplier, BiConsumer) */ @ParallelSupported @TerminalOp public abstract R collect(Supplier supplier, ObjLongConsumer accumulator); @ParallelSupported @TerminalOp public abstract void forEach(final Throwables.LongConsumer action) throws E; @ParallelSupported @TerminalOp public abstract void forEachIndexed(Throwables.IndexedLongConsumer action) throws E; @ParallelSupported @TerminalOp public abstract boolean anyMatch(final Throwables.LongPredicate predicate) throws E; @ParallelSupported @TerminalOp public abstract boolean allMatch(final Throwables.LongPredicate predicate) throws E; @ParallelSupported @TerminalOp public abstract boolean noneMatch(final Throwables.LongPredicate predicate) throws E; @ParallelSupported @TerminalOp public abstract OptionalLong findFirst(final Throwables.LongPredicate predicate) throws E; /** * Consider using: {@code stream.reversed().findFirst(predicate)} for better performance if possible. * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract OptionalLong findLast(final Throwables.LongPredicate predicate) throws E; @ParallelSupported @TerminalOp public abstract OptionalLong findAny(final Throwables.LongPredicate predicate) throws E; @SequentialOnly @TerminalOp public abstract OptionalLong findFirstOrLast(Throwables.LongPredicate predicateForFirst, Throwables.LongPredicate predicateForLast) throws E, E2; @SequentialOnly @TerminalOp public abstract OptionalLong min(); @SequentialOnly @TerminalOp public abstract OptionalLong max(); /** * * @param k * @return OptionalByte.empty() if there is no element or count less than k, otherwise the kth largest element. */ @SequentialOnly @TerminalOp public abstract OptionalLong kthLargest(int k); @SequentialOnly @TerminalOp public abstract long sum(); @SequentialOnly @TerminalOp public abstract OptionalDouble average(); @SequentialOnly @TerminalOp public abstract LongSummaryStatistics summarize(); @SequentialOnly @TerminalOp public abstract Pair>> summarizeAndPercentiles(); /** * * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return * @deprecated replaced by {@code mergeWith(LongStream, LongBiFunction)} * @see #mergeWith(LongStream, LongBiFunction) */ @SequentialOnly @IntermediateOp @Deprecated public LongStream merge(final LongStream b, final LongBiFunction nextSelector) { return mergeWith(b, nextSelector); } /** * * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ @SequentialOnly @IntermediateOp public abstract LongStream mergeWith(final LongStream b, final LongBiFunction nextSelector); @ParallelSupported @IntermediateOp public abstract LongStream zipWith(LongStream b, LongBinaryOperator zipFunction); @ParallelSupported @IntermediateOp public abstract LongStream zipWith(LongStream b, LongStream c, LongTernaryOperator zipFunction); @ParallelSupported @IntermediateOp public abstract LongStream zipWith(LongStream b, long valueForNoneA, long valueForNoneB, LongBinaryOperator zipFunction); @ParallelSupported @IntermediateOp public abstract LongStream zipWith(LongStream b, LongStream c, long valueForNoneA, long valueForNoneB, long valueForNoneC, LongTernaryOperator zipFunction); @SequentialOnly @IntermediateOp @Deprecated public abstract FloatStream asFloatStream(); @SequentialOnly @IntermediateOp public abstract DoubleStream asDoubleStream(); @SequentialOnly @IntermediateOp public abstract java.util.stream.LongStream toJdkStream(); @SequentialOnly @IntermediateOp public abstract Stream boxed(); /** * Remember to close this Stream after the iteration is done, if needed. * * @return */ @SequentialOnly @Override public LongIterator iterator() { assertNotClosed(); if (!isEmptyCloseHandlers(closeHandlers) && logger.isWarnEnabled()) { logger.warn("### Remember to close " + ClassUtil.getSimpleClassName(getClass())); } return iteratorEx(); } abstract LongIteratorEx iteratorEx(); public static LongStream empty() { return new ArrayLongStream(N.EMPTY_LONG_ARRAY, true, null); } public static LongStream ofNullable(final Long e) { return e == null ? empty() : of(e); } @SafeVarargs public static LongStream of(final long... a) { return N.isNullOrEmpty(a) ? empty() : new ArrayLongStream(a); } public static LongStream of(final long[] a, final int startIndex, final int endIndex) { return N.isNullOrEmpty(a) && (startIndex == 0 && endIndex == 0) ? empty() : new ArrayLongStream(a, startIndex, endIndex); } public static LongStream of(final Long[] a) { return Stream.of(a).mapToLong(FnL.unbox()); } public static LongStream of(final Long[] a, final int startIndex, final int endIndex) { return Stream.of(a, startIndex, endIndex).mapToLong(FnL.unbox()); } public static LongStream of(final Collection c) { return Stream.of(c).mapToLong(FnL.unbox()); } public static LongStream of(final LongIterator iterator) { return iterator == null ? empty() : new IteratorLongStream(iterator); } public static LongStream of(final java.util.stream.LongStream stream) { if (stream == null) { return empty(); } return of(new LongIteratorEx() { private PrimitiveIterator.OfLong iter = null; @Override public boolean hasNext() { if (iter == null) { iter = stream.iterator(); } return iter.hasNext(); } @Override public long nextLong() { if (iter == null) { iter = stream.iterator(); } return iter.nextLong(); } @Override public long count() { return iter == null ? stream.count() : super.count(); } @Override public void advance(long n) { if (iter == null) { iter = stream.skip(n).iterator(); } else { super.advance(n); } } @Override public long[] toArray() { return iter == null ? stream.toArray() : super.toArray(); } }).__(s -> stream.isParallel() ? s.parallel() : s.sequential()).onClose(() -> stream.close()); } public static LongStream of(final LongBuffer buf) { if (buf == null) { return empty(); } return IntStream.range(buf.position(), buf.limit()).mapToLong(buf::get); } public static LongStream of(final OptionalLong op) { return op == null || !op.isPresent() ? LongStream.empty() : LongStream.of(op.get()); } public static LongStream of(final java.util.OptionalLong op) { return op == null || !op.isPresent() ? LongStream.empty() : LongStream.of(op.getAsLong()); } /** * Lazy evaluation. *
* * This is equal to: {@code Stream.just(supplier).flatMapToLong(it -> it.get())}. * * @param * @param supplier * @return */ public static LongStream defer(final Supplier supplier) { N.checkArgNotNull(supplier, "supplier"); return Stream.just(supplier).flatMapToLong(Supplier::get); } /** * Lazy evaluation. *
* * This is equal to: {@code Stream.just(supplier).flatMapToLong(it -> it.get().stream())}. * * @param supplier * @return */ @Beta public static LongStream from(final Supplier supplier) { N.checkArgNotNull(supplier, "supplier"); return Stream.just(supplier).flatMapToLong(it -> it.get().stream()); } private static final Function flatMapper = t -> LongStream.of(t); private static final Function flatMappper = t -> LongStream.flatten(t); public static LongStream flatten(final long[][] a) { return N.isNullOrEmpty(a) ? empty() : Stream.of(a).flatMapToLong(flatMapper); } public static LongStream flatten(final long[][] a, final boolean vertically) { if (N.isNullOrEmpty(a)) { return empty(); } else if (a.length == 1) { return of(a[0]); } else if (!vertically) { return Stream.of(a).flatMapToLong(flatMapper); } long n = 0; for (long[] e : a) { n += N.len(e); } if (n == 0) { return empty(); } final int rows = N.len(a); final long count = n; final LongIterator iter = new LongIteratorEx() { private int rowNum = 0; private int colNum = 0; private long cnt = 0; @Override public boolean hasNext() { return cnt < count; } @Override public long nextLong() { if (cnt++ >= count) { throw new NoSuchElementException(); } if (rowNum == rows) { rowNum = 0; colNum++; } while (a[rowNum] == null || colNum >= a[rowNum].length) { if (rowNum < rows - 1) { rowNum++; } else { rowNum = 0; colNum++; } } return a[rowNum++][colNum]; } }; return of(iter); } public static LongStream flatten(final long[][] a, final long valueForNone, final boolean vertically) { if (N.isNullOrEmpty(a)) { return empty(); } else if (a.length == 1) { return of(a[0]); } long n = 0; int maxLen = 0; for (long[] e : a) { n += N.len(e); maxLen = N.max(maxLen, N.len(e)); } if (n == 0) { return empty(); } final int rows = N.len(a); final int cols = maxLen; final long count = rows * cols; LongIterator iter = null; if (vertically) { iter = new LongIteratorEx() { private int rowNum = 0; private int colNum = 0; private long cnt = 0; @Override public boolean hasNext() { return cnt < count; } @Override public long nextLong() { if (cnt++ >= count) { throw new NoSuchElementException(); } if (rowNum == rows) { rowNum = 0; colNum++; } if (a[rowNum] == null || colNum >= a[rowNum].length) { rowNum++; return valueForNone; } else { return a[rowNum++][colNum]; } } }; } else { iter = new LongIteratorEx() { private int rowNum = 0; private int colNum = 0; private long cnt = 0; @Override public boolean hasNext() { return cnt < count; } @Override public long nextLong() { if (cnt++ >= count) { throw new NoSuchElementException(); } if (colNum >= cols) { colNum = 0; rowNum++; } if (a[rowNum] == null || colNum >= a[rowNum].length) { colNum++; return valueForNone; } else { return a[rowNum][colNum++]; } } }; } return of(iter); } public static LongStream flatten(final long[][][] a) { return N.isNullOrEmpty(a) ? empty() : Stream.of(a).flatMapToLong(flatMappper); } public static LongStream range(final long startInclusive, final long endExclusive) { if (startInclusive >= endExclusive) { return empty(); } else if (endExclusive - startInclusive < 0) { final long m = BigInteger.valueOf(endExclusive).subtract(BigInteger.valueOf(startInclusive)).divide(BigInteger.valueOf(3)).longValue(); return concat(range(startInclusive, startInclusive + m), range(startInclusive + m, (startInclusive + m) + m), range((startInclusive + m) + m, endExclusive)); } return new IteratorLongStream(new LongIteratorEx() { private long next = startInclusive; private long cnt = endExclusive - startInclusive; @Override public boolean hasNext() { return cnt > 0; } @Override public long nextLong() { if (cnt-- <= 0) { throw new NoSuchElementException(); } return next++; } @Override public void advance(long n) { cnt = n >= cnt ? 0 : cnt - n; next += n; } @Override public long count() { return cnt; } @Override public long[] toArray() { final long[] result = new long[(int) cnt]; for (int i = 0; i < cnt; i++) { result[i] = next++; } cnt = 0; return result; } }); } public static LongStream range(final long startInclusive, final long endExclusive, final long by) { if (by == 0) { throw new IllegalArgumentException("'by' can't be zero"); } if (endExclusive == startInclusive || endExclusive > startInclusive != by > 0) { return empty(); } if ((by > 0 && endExclusive - startInclusive < 0) || (by < 0 && startInclusive - endExclusive < 0)) { long m = BigInteger.valueOf(endExclusive).subtract(BigInteger.valueOf(startInclusive)).divide(BigInteger.valueOf(3)).longValue(); if ((by > 0 && by > m) || (by < 0 && by < m)) { return concat(range(startInclusive, startInclusive + by), range(startInclusive + by, endExclusive)); } else { m = m > 0 ? m - m % by : m + m % by; return concat(range(startInclusive, startInclusive + m, by), range(startInclusive + m, (startInclusive + m) + m, by), range((startInclusive + m) + m, endExclusive, by)); } } return new IteratorLongStream(new LongIteratorEx() { private long next = startInclusive; private long cnt = (endExclusive - startInclusive) / by + ((endExclusive - startInclusive) % by == 0 ? 0 : 1); @Override public boolean hasNext() { return cnt > 0; } @Override public long nextLong() { if (cnt-- <= 0) { throw new NoSuchElementException(); } long result = next; next += by; return result; } @Override public void advance(long n) { cnt = n >= cnt ? 0 : cnt - n; next += n * by; } @Override public long count() { return cnt; } @Override public long[] toArray() { final long[] result = new long[(int) cnt]; for (int i = 0; i < cnt; i++, next += by) { result[i] = next; } cnt = 0; return result; } }); } public static LongStream rangeClosed(final long startInclusive, final long endInclusive) { if (startInclusive > endInclusive) { return empty(); } else if (startInclusive == endInclusive) { return of(startInclusive); } else if (endInclusive - startInclusive + 1 <= 0) { final long m = BigInteger.valueOf(endInclusive).subtract(BigInteger.valueOf(startInclusive)).divide(BigInteger.valueOf(3)).longValue(); return concat(range(startInclusive, startInclusive + m), range(startInclusive + m, (startInclusive + m) + m), rangeClosed((startInclusive + m) + m, endInclusive)); } return new IteratorLongStream(new LongIteratorEx() { private long next = startInclusive; private long cnt = endInclusive - startInclusive + 1; @Override public boolean hasNext() { return cnt > 0; } @Override public long nextLong() { if (cnt-- <= 0) { throw new NoSuchElementException(); } return next++; } @Override public void advance(long n) { cnt = n >= cnt ? 0 : cnt - n; next += n; } @Override public long count() { return cnt; } @Override public long[] toArray() { final long[] result = new long[(int) cnt]; for (int i = 0; i < cnt; i++) { result[i] = next++; } cnt = 0; return result; } }); } public static LongStream rangeClosed(final long startInclusive, final long endInclusive, final long by) { if (by == 0) { throw new IllegalArgumentException("'by' can't be zero"); } if (endInclusive == startInclusive) { return of(startInclusive); } else if (endInclusive > startInclusive != by > 0) { return empty(); } if ((by > 0 && endInclusive - startInclusive < 0) || (by < 0 && startInclusive - endInclusive < 0) || ((endInclusive - startInclusive) / by + 1 <= 0)) { long m = BigInteger.valueOf(endInclusive).subtract(BigInteger.valueOf(startInclusive)).divide(BigInteger.valueOf(3)).longValue(); if ((by > 0 && by > m) || (by < 0 && by < m)) { return concat(range(startInclusive, startInclusive + by), rangeClosed(startInclusive + by, endInclusive)); } else { m = m > 0 ? m - m % by : m + m % by; return concat(range(startInclusive, startInclusive + m, by), range(startInclusive + m, (startInclusive + m) + m, by), rangeClosed((startInclusive + m) + m, endInclusive, by)); } } return new IteratorLongStream(new LongIteratorEx() { private long next = startInclusive; private long cnt = (endInclusive - startInclusive) / by + 1; @Override public boolean hasNext() { return cnt > 0; } @Override public long nextLong() { if (cnt-- <= 0) { throw new NoSuchElementException(); } long result = next; next += by; return result; } @Override public void advance(long n) { cnt = n >= cnt ? 0 : cnt - n; next += n * by; } @Override public long count() { return cnt; } @Override public long[] toArray() { final long[] result = new long[(int) cnt]; for (int i = 0; i < cnt; i++, next += by) { result[i] = next; } cnt = 0; return result; } }); } public static LongStream repeat(final long element, final long n) { N.checkArgNotNegative(n, "n"); if (n == 0) { return empty(); } else if (n < 10) { return of(Array.repeat(element, (int) n)); } return new IteratorLongStream(new LongIteratorEx() { private long cnt = n; @Override public boolean hasNext() { return cnt > 0; } @Override public long nextLong() { if (cnt-- <= 0) { throw new NoSuchElementException(); } return element; } @Override public void advance(long n) { cnt = n >= cnt ? 0 : cnt - (int) n; } @Override public long count() { return cnt; } @Override public long[] toArray() { final long[] result = new long[(int) cnt]; for (int i = 0; i < cnt; i++) { result[i] = element; } cnt = 0; return result; } }); } public static LongStream random() { return generate(() -> RAND.nextLong()); } public static LongStream iterate(final BooleanSupplier hasNext, final LongSupplier next) { N.checkArgNotNull(hasNext); N.checkArgNotNull(next); return new IteratorLongStream(new LongIteratorEx() { private boolean hasNextVal = false; @Override public boolean hasNext() { if (!hasNextVal) { hasNextVal = hasNext.getAsBoolean(); } return hasNextVal; } @Override public long nextLong() { if (!hasNextVal && !hasNext()) { throw new NoSuchElementException(); } hasNextVal = false; return next.getAsLong(); } }); } public static LongStream iterate(final long init, final BooleanSupplier hasNext, final LongUnaryOperator f) { N.checkArgNotNull(hasNext); N.checkArgNotNull(f); return new IteratorLongStream(new LongIteratorEx() { private long t = 0; private boolean isFirst = true; private boolean hasNextVal = false; @Override public boolean hasNext() { if (!hasNextVal) { hasNextVal = hasNext.getAsBoolean(); } return hasNextVal; } @Override public long nextLong() { if (!hasNextVal && !hasNext()) { throw new NoSuchElementException(); } hasNextVal = false; if (isFirst) { isFirst = false; t = init; } else { t = f.applyAsLong(t); } return t; } }); } /** * * @param init * @param hasNext test if has next by hasNext.test(init) for first time and hasNext.test(f.apply(previous)) for remaining. * @param f * @return */ public static LongStream iterate(final long init, final LongPredicate hasNext, final LongUnaryOperator f) { N.checkArgNotNull(hasNext); N.checkArgNotNull(f); return new IteratorLongStream(new LongIteratorEx() { private long t = 0; private long cur = 0; private boolean isFirst = true; private boolean hasMore = true; private boolean hasNextVal = false; @Override public boolean hasNext() { if (!hasNextVal && hasMore) { if (isFirst) { isFirst = false; hasNextVal = hasNext.test(cur = init); } else { hasNextVal = hasNext.test(cur = f.applyAsLong(t)); } if (!hasNextVal) { hasMore = false; } } return hasNextVal; } @Override public long nextLong() { if (!hasNextVal && !hasNext()) { throw new NoSuchElementException(); } t = cur; hasNextVal = false; return t; } }); } public static LongStream iterate(final long init, final LongUnaryOperator f) { N.checkArgNotNull(f); return new IteratorLongStream(new LongIteratorEx() { private long t = 0; private boolean isFirst = true; @Override public boolean hasNext() { return true; } @Override public long nextLong() { if (isFirst) { isFirst = false; t = init; } else { t = f.applyAsLong(t); } return t; } }); } public static LongStream generate(final LongSupplier s) { N.checkArgNotNull(s); return new IteratorLongStream(new LongIteratorEx() { @Override public boolean hasNext() { return true; } @Override public long nextLong() { return s.getAsLong(); } }); } /** * * @param intervalInMillis * @return */ public static LongStream interval(final long intervalInMillis) { return interval(0, intervalInMillis); } /** * Generates the long value by the specified period: [0, 1, 2, 3...] * * @param delayInMillis * @param intervalInMillis * @return */ public static LongStream interval(final long delayInMillis, final long intervalInMillis) { return interval(delayInMillis, intervalInMillis, TimeUnit.MILLISECONDS); } /** * Generates the long value by the specified period: [0, 1, 2, 3...] * * @param delay * @param interval * @param unit * @return */ public static LongStream interval(final long delay, final long interval, final TimeUnit unit) { return of(new LongIteratorEx() { private final long intervalInMillis = unit.toMillis(interval); private long nextTime = System.currentTimeMillis() + unit.toMillis(delay); private long val = 0; @Override public boolean hasNext() { return true; } @Override public long nextLong() { long now = System.currentTimeMillis(); if (now < nextTime) { N.sleep(nextTime - now); } nextTime += intervalInMillis; return val++; } }); } @SafeVarargs public static LongStream concat(final long[]... a) { if (N.isNullOrEmpty(a)) { return empty(); } return concat(Arrays.asList(a)); } @SafeVarargs public static LongStream concat(final LongIterator... a) { if (N.isNullOrEmpty(a)) { return empty(); } return concatIterators(Array.asList(a)); } @SafeVarargs public static LongStream concat(final LongStream... a) { if (N.isNullOrEmpty(a)) { return empty(); } return concat(Array.asList(a)); } @Beta public static LongStream concat(final List c) { if (N.isNullOrEmpty(c)) { return empty(); } return of(new LongIteratorEx() { private final Iterator iter = c.iterator(); private long[] cur; private int cursor = 0; @Override public boolean hasNext() { while ((N.isNullOrEmpty(cur) || cursor >= cur.length) && iter.hasNext()) { cur = iter.next(); cursor = 0; } return cur != null && cursor < cur.length; } @Override public long nextLong() { if ((cur == null || cursor >= cur.length) && !hasNext()) { throw new NoSuchElementException(); } return cur[cursor++]; } }); } public static LongStream concat(final Collection c) { return N.isNullOrEmpty(c) ? empty() : new IteratorLongStream(new LongIteratorEx() { private final Iterator iterators = c.iterator(); private LongStream cur; private LongIterator iter; @Override public boolean hasNext() { while ((iter == null || !iter.hasNext()) && iterators.hasNext()) { if (cur != null) { cur.close(); } cur = iterators.next(); iter = cur == null ? null : cur.iteratorEx(); } return iter != null && iter.hasNext(); } @Override public long nextLong() { if ((iter == null || !iter.hasNext()) && !hasNext()) { throw new NoSuchElementException(); } return iter.nextLong(); } }).onClose(newCloseHandler(c)); } @Beta public static LongStream concatIterators(final Collection c) { if (N.isNullOrEmpty(c)) { return empty(); } return new IteratorLongStream(new LongIteratorEx() { private final Iterator iter = c.iterator(); private LongIterator cur; @Override public boolean hasNext() { while ((cur == null || !cur.hasNext()) && iter.hasNext()) { cur = iter.next(); } return cur != null && cur.hasNext(); } @Override public long nextLong() { if ((cur == null || !cur.hasNext()) && !hasNext()) { throw new NoSuchElementException(); } return cur.nextLong(); } }); } /** * Zip together the "a" and "b" arrays until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static LongStream zip(final long[] a, final long[] b, final LongBinaryOperator zipFunction) { if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) { return empty(); } return new IteratorLongStream(new LongIteratorEx() { private final int len = N.min(N.len(a), N.len(b)); private int cursor = 0; @Override public boolean hasNext() { return cursor < len; } @Override public long nextLong() { if (cursor >= len) { throw new NoSuchElementException(); } return zipFunction.applyAsLong(a[cursor], b[cursor++]); } }); } /** * Zip together the "a", "b" and "c" arrays until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param c * @return */ public static LongStream zip(final long[] a, final long[] b, final long[] c, final LongTernaryOperator zipFunction) { if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b) || N.isNullOrEmpty(c)) { return empty(); } return new IteratorLongStream(new LongIteratorEx() { private final int len = N.min(N.len(a), N.len(b), N.len(c)); private int cursor = 0; @Override public boolean hasNext() { return cursor < len; } @Override public long nextLong() { if (cursor >= len) { throw new NoSuchElementException(); } return zipFunction.applyAsLong(a[cursor], b[cursor], c[cursor++]); } }); } /** * Zip together the "a" and "b" iterators until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static LongStream zip(final LongIterator a, final LongIterator b, final LongBinaryOperator zipFunction) { return new IteratorLongStream(new LongIteratorEx() { private final LongIterator iterA = a == null ? LongIterator.empty() : a; private final LongIterator iterB = b == null ? LongIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext(); } @Override public long nextLong() { return zipFunction.applyAsLong(iterA.nextLong(), iterB.nextLong()); } }); } /** * Zip together the "a", "b" and "c" iterators until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static LongStream zip(final LongIterator a, final LongIterator b, final LongIterator c, final LongTernaryOperator zipFunction) { return new IteratorLongStream(new LongIteratorEx() { private final LongIterator iterA = a == null ? LongIterator.empty() : a; private final LongIterator iterB = b == null ? LongIterator.empty() : b; private final LongIterator iterC = c == null ? LongIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public long nextLong() { return zipFunction.applyAsLong(iterA.nextLong(), iterB.nextLong(), iterC.nextLong()); } }); } /** * Zip together the "a" and "b" streams until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static LongStream zip(final LongStream a, final LongStream b, final LongBinaryOperator zipFunction) { return zip(iterate(a), iterate(b), zipFunction).onClose(newCloseHandler(a, b)); } /** * Zip together the "a", "b" and "c" streams until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static LongStream zip(final LongStream a, final LongStream b, final LongStream c, final LongTernaryOperator zipFunction) { return zip(iterate(a), iterate(b), iterate(c), zipFunction).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until one of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param c * @param zipFunction * @return */ public static LongStream zip(final Collection c, final LongNFunction zipFunction) { return Stream.zip(c, zipFunction).mapToLong(ToLongFunction.UNBOX); } /** * Zip together the "a" and "b" iterators until all of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param valueForNoneA value to fill if "a" runs out of values first. * @param valueForNoneB value to fill if "b" runs out of values first. * @param zipFunction * @return */ public static LongStream zip(final long[] a, final long[] b, final long valueForNoneA, final long valueForNoneB, final LongBinaryOperator zipFunction) { if (N.isNullOrEmpty(a) && N.isNullOrEmpty(b)) { return empty(); } return new IteratorLongStream(new LongIteratorEx() { private final int aLen = N.len(a), bLen = N.len(b), len = N.max(aLen, bLen); private int cursor = 0; private long ret = 0; @Override public boolean hasNext() { return cursor < len; } @Override public long nextLong() { if (cursor >= len) { throw new NoSuchElementException(); } ret = zipFunction.applyAsLong(cursor < aLen ? a[cursor] : valueForNoneA, cursor < bLen ? b[cursor] : valueForNoneB); cursor++; return ret; } }); } /** * Zip together the "a", "b" and "c" iterators until all of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param c * @param valueForNoneA value to fill if "a" runs out of values. * @param valueForNoneB value to fill if "b" runs out of values. * @param valueForNoneC value to fill if "c" runs out of values. * @param zipFunction * @return */ public static LongStream zip(final long[] a, final long[] b, final long[] c, final long valueForNoneA, final long valueForNoneB, final long valueForNoneC, final LongTernaryOperator zipFunction) { if (N.isNullOrEmpty(a) && N.isNullOrEmpty(b) && N.isNullOrEmpty(c)) { return empty(); } return new IteratorLongStream(new LongIteratorEx() { private final int aLen = N.len(a), bLen = N.len(b), cLen = N.len(c), len = N.max(aLen, bLen, cLen); private int cursor = 0; private long ret = 0; @Override public boolean hasNext() { return cursor < len; } @Override public long nextLong() { if (cursor >= len) { throw new NoSuchElementException(); } ret = zipFunction.applyAsLong(cursor < aLen ? a[cursor] : valueForNoneA, cursor < bLen ? b[cursor] : valueForNoneB, cursor < cLen ? c[cursor] : valueForNoneC); cursor++; return ret; } }); } /** * Zip together the "a" and "b" iterators until all of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param valueForNoneA value to fill if "a" runs out of values first. * @param valueForNoneB value to fill if "b" runs out of values first. * @param zipFunction * @return */ public static LongStream zip(final LongIterator a, final LongIterator b, final long valueForNoneA, final long valueForNoneB, final LongBinaryOperator zipFunction) { return new IteratorLongStream(new LongIteratorEx() { private final LongIterator iterA = a == null ? LongIterator.empty() : a; private final LongIterator iterB = b == null ? LongIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext(); } @Override public long nextLong() { if (iterA.hasNext()) { return zipFunction.applyAsLong(iterA.nextLong(), iterB.hasNext() ? iterB.nextLong() : valueForNoneB); } else { return zipFunction.applyAsLong(valueForNoneA, iterB.nextLong()); } } }); } /** * Zip together the "a", "b" and "c" iterators until all of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param c * @param valueForNoneA value to fill if "a" runs out of values. * @param valueForNoneB value to fill if "b" runs out of values. * @param valueForNoneC value to fill if "c" runs out of values. * @param zipFunction * @return */ public static LongStream zip(final LongIterator a, final LongIterator b, final LongIterator c, final long valueForNoneA, final long valueForNoneB, final long valueForNoneC, final LongTernaryOperator zipFunction) { return new IteratorLongStream(new LongIteratorEx() { private final LongIterator iterA = a == null ? LongIterator.empty() : a; private final LongIterator iterB = b == null ? LongIterator.empty() : b; private final LongIterator iterC = c == null ? LongIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public long nextLong() { if (iterA.hasNext()) { return zipFunction.applyAsLong(iterA.nextLong(), iterB.hasNext() ? iterB.nextLong() : valueForNoneB, iterC.hasNext() ? iterC.nextLong() : valueForNoneC); } else if (iterB.hasNext()) { return zipFunction.applyAsLong(valueForNoneA, iterB.nextLong(), iterC.hasNext() ? iterC.nextLong() : valueForNoneC); } else { return zipFunction.applyAsLong(valueForNoneA, valueForNoneB, iterC.nextLong()); } } }); } /** * Zip together the "a" and "b" iterators until all of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param valueForNoneA value to fill if "a" runs out of values first. * @param valueForNoneB value to fill if "b" runs out of values first. * @param zipFunction * @return */ public static LongStream zip(final LongStream a, final LongStream b, final long valueForNoneA, final long valueForNoneB, final LongBinaryOperator zipFunction) { return zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction).onClose(newCloseHandler(a, b)); } /** * Zip together the "a", "b" and "c" iterators until all of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param c * @param valueForNoneA value to fill if "a" runs out of values. * @param valueForNoneB value to fill if "b" runs out of values. * @param valueForNoneC value to fill if "c" runs out of values. * @param zipFunction * @return */ public static LongStream zip(final LongStream a, final LongStream b, final LongStream c, final long valueForNoneA, final long valueForNoneB, final long valueForNoneC, final LongTernaryOperator zipFunction) { return zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until all of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param c * @param valuesForNone value to fill for any iterator runs out of values. * @param zipFunction * @return */ public static LongStream zip(final Collection c, final long[] valuesForNone, final LongNFunction zipFunction) { return Stream.zip(c, valuesForNone, zipFunction).mapToLong(ToLongFunction.UNBOX); } /** * * @param a * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static LongStream merge(final long[] a, final long[] b, final LongBiFunction nextSelector) { if (N.isNullOrEmpty(a)) { return of(b); } else if (N.isNullOrEmpty(b)) { return of(a); } return new IteratorLongStream(new LongIteratorEx() { private final int lenA = a.length; private final int lenB = b.length; private int cursorA = 0; private int cursorB = 0; @Override public boolean hasNext() { return cursorA < lenA || cursorB < lenB; } @Override public long nextLong() { if (cursorA < lenA) { if (cursorB < lenB) { if (nextSelector.apply(a[cursorA], b[cursorB]) == MergeResult.TAKE_FIRST) { return a[cursorA++]; } else { return b[cursorB++]; } } else { return a[cursorA++]; } } else if (cursorB < lenB) { return b[cursorB++]; } else { throw new NoSuchElementException(); } } }); } /** * * @param a * @param b * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static LongStream merge(final long[] a, final long[] b, final long[] c, final LongBiFunction nextSelector) { return merge(merge(a, b, nextSelector).iteratorEx(), LongStream.of(c).iteratorEx(), nextSelector); } /** * * @param a * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static LongStream merge(final LongIterator a, final LongIterator b, final LongBiFunction nextSelector) { return new IteratorLongStream(new LongIteratorEx() { private final LongIterator iterA = a == null ? LongIterator.empty() : a; private final LongIterator iterB = b == null ? LongIterator.empty() : b; private long nextA = 0; private long nextB = 0; private boolean hasNextA = false; private boolean hasNextB = false; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || hasNextA || hasNextB; } @Override public long nextLong() { if (hasNextA) { if (iterB.hasNext()) { if (nextSelector.apply(nextA, (nextB = iterB.nextLong())) == MergeResult.TAKE_FIRST) { hasNextA = false; hasNextB = true; return nextA; } else { return nextB; } } else { hasNextA = false; return nextA; } } else if (hasNextB) { if (iterA.hasNext()) { if (nextSelector.apply((nextA = iterA.nextLong()), nextB) == MergeResult.TAKE_FIRST) { return nextA; } else { hasNextA = true; hasNextB = false; return nextB; } } else { hasNextB = false; return nextB; } } else if (iterA.hasNext()) { if (iterB.hasNext()) { if (nextSelector.apply((nextA = iterA.nextLong()), (nextB = iterB.nextLong())) == MergeResult.TAKE_FIRST) { hasNextB = true; return nextA; } else { hasNextA = true; return nextB; } } else { return iterA.nextLong(); } } else if (iterB.hasNext()) { return iterB.nextLong(); } else { throw new NoSuchElementException(); } } }); } /** * * @param a * @param b * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static LongStream merge(final LongIterator a, final LongIterator b, final LongIterator c, final LongBiFunction nextSelector) { return merge(merge(a, b, nextSelector).iteratorEx(), c, nextSelector); } /** * * @param a * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static LongStream merge(final LongStream a, final LongStream b, final LongBiFunction nextSelector) { return merge(iterate(a), iterate(b), nextSelector).onClose(newCloseHandler(a, b)); } /** * * @param a * @param b * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static LongStream merge(final LongStream a, final LongStream b, final LongStream c, final LongBiFunction nextSelector) { return merge(merge(a, b, nextSelector), c, nextSelector); } /** * * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static LongStream merge(final Collection c, final LongBiFunction nextSelector) { if (N.isNullOrEmpty(c)) { return empty(); } else if (c.size() == 1) { return c.iterator().next(); } else if (c.size() == 2) { final Iterator iter = c.iterator(); return merge(iter.next(), iter.next(), nextSelector); } final Iterator iter = c.iterator(); LongStream result = merge(iter.next(), iter.next(), nextSelector); while (iter.hasNext()) { result = merge(result, iter.next(), nextSelector); } return result; } /** * All the elements from each input {@code Collection/Iterator/Stream} will be merged into two queues by multiple threads. * Then these two new queues will be merged into one {@code Iterator/Stream} by one thread. * So it's not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the new queues. * Consider using {@code merge}, which is totally lazy evaluation. * * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static LongStream parallelMerge(final Collection c, final LongBiFunction nextSelector) { return parallelMerge(c, nextSelector, DEFAULT_MAX_THREAD_NUM); } /** * All the elements from each input {@code Collection/Iterator/Stream} will be merged into two queues by multiple threads. * Then these two new queues will be merged into one {@code Iterator/Stream} by one thread. * So it's not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the new queues. * Consider using {@code merge}, which is totally lazy evaluation. * * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @param maxThreadNum * @return */ public static LongStream parallelMerge(final Collection c, final LongBiFunction nextSelector, final int maxThreadNum) { N.checkArgument(maxThreadNum > 0, "'maxThreadNum' must not less than 1"); if (maxThreadNum <= 1) { return merge(c, nextSelector); } else if (N.isNullOrEmpty(c)) { return empty(); } else if (c.size() == 1) { return c.iterator().next(); } else if (c.size() == 2) { final Iterator iter = c.iterator(); return merge(iter.next(), iter.next(), nextSelector); } else if (c.size() == 3) { final Iterator iter = c.iterator(); return merge(iter.next(), iter.next(), iter.next(), nextSelector); } final Supplier supplier = () -> { final Queue queue = N.newLinkedList(); queue.addAll(c); final Holder eHolder = new Holder<>(); final MutableInt cnt = MutableInt.of(c.size()); final List> futureList = new ArrayList<>(c.size() - 1); final int threadNum = N.min(maxThreadNum, c.size() / 2 + 1); AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(DEFAULT_ASYNC_EXECUTOR, threadNum); for (int i = 0; i < threadNum; i++) { asyncExecutorToUse = execute(asyncExecutorToUse, threadNum - i, futureList, () -> { LongStream a = null; LongStream b = null; LongStream c1 = null; try { while (eHolder.value() == null) { synchronized (queue) { if (cnt.intValue() > 2 && queue.size() > 1) { a = queue.poll(); b = queue.poll(); cnt.decrement(); } else { break; } } c1 = LongStream.of(merge(a, b, nextSelector).toArray()); synchronized (queue) { queue.offer(c1); } } } catch (Throwable e) { setError(eHolder, e); } }); } completeAndShutdownTempExecutor(futureList, eHolder, c, asyncExecutorToUse); return merge(queue.poll(), queue.poll(), nextSelector); }; return Stream.just(supplier).flatMapToLong(Supplier::get); } public static abstract class LongStreamEx extends LongStream { private LongStreamEx(boolean sorted, Collection closeHandlers) { super(sorted, closeHandlers); // Factory class. } } }