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

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

/*
 * 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.nio.IntBuffer;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.IntSummaryStatistics;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.PrimitiveIterator;
import java.util.Random;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.function.IntPredicate;
import java.util.function.IntSupplier;
import java.util.function.IntToDoubleFunction;
import java.util.function.IntToLongFunction;
import java.util.function.IntUnaryOperator;
import java.util.function.ObjIntConsumer;
import java.util.function.Supplier;
import java.util.stream.Collector;

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.Fn.BiConsumers;
import com.landawn.abacus.util.Fn.FI;
import com.landawn.abacus.util.IndexedInt;
import com.landawn.abacus.util.IntIterator;
import com.landawn.abacus.util.IntList;
import com.landawn.abacus.util.InternalUtil;
import com.landawn.abacus.util.MergeResult;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.Pair;
import com.landawn.abacus.util.Percentage;
import com.landawn.abacus.util.Strings;
import com.landawn.abacus.util.Throwables;
import com.landawn.abacus.util.cs;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalInt;
import com.landawn.abacus.util.function.IntBiFunction;
import com.landawn.abacus.util.function.IntBiPredicate;
import com.landawn.abacus.util.function.IntMapMultiConsumer;
import com.landawn.abacus.util.function.IntNFunction;
import com.landawn.abacus.util.function.IntTernaryOperator;
import com.landawn.abacus.util.function.IntToByteFunction;
import com.landawn.abacus.util.function.IntToCharFunction;
import com.landawn.abacus.util.function.IntToFloatFunction;
import com.landawn.abacus.util.function.IntToShortFunction;
import com.landawn.abacus.util.function.IntTriPredicate;
import com.landawn.abacus.util.function.ObjIntFunction;
import com.landawn.abacus.util.function.ToIntFunction;
import com.landawn.abacus.util.function.TriFunction;

/**
 * The IntStream class is an abstract class that represents a stream of int elements and supports different kinds of computations. 
* The Stream operations are divided into intermediate and terminal operations, and are combined to form stream pipelines.
* *
* The Stream will be automatically closed after a terminal method is called/triggered. * *
*
* Refer to {@code com.landawn.abacus.util.stream.BaseStream} and {@code com.landawn.abacus.util.stream.Stream} for more APIs docs. * * @see com.landawn.abacus.util.stream.Stream * @see com.landawn.abacus.util.stream.BaseStream */ @com.landawn.abacus.annotation.Immutable @LazyEvaluation public abstract class IntStream extends StreamBase { static final Random RAND = new SecureRandom(); IntStream(final boolean sorted, final Collection closeHandlers) { super(sorted, null, closeHandlers); } /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract IntStream map(IntUnaryOperator mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract CharStream mapToChar(IntToCharFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract ByteStream mapToByte(IntToByteFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract ShortStream mapToShort(IntToShortFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract LongStream mapToLong(IntToLongFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract FloatStream mapToFloat(IntToFloatFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract DoubleStream mapToDouble(IntToDoubleFunction mapper); /** * * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream mapToObj(IntFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract IntStream flatMap(IntFunction mapper); // public abstract IntStream flatmap(IntFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract IntStream flatmap(IntFunction mapper); //NOSONAR /** * * @param mapper * @return * @deprecated should use {@code flatmapToObj(IntFunction> mapper)} instead * @see #flatmapToObj(IntFunction) */ @Deprecated @ParallelSupported @IntermediateOp IntStream flattMap(@SuppressWarnings("unused") final IntFunction> mapper) throws UnsupportedOperationException { // NOSONAR throw new UnsupportedOperationException(); } /** * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract IntStream flattmap(IntFunction mapper); //NOSONAR /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract CharStream flatMapToChar(IntFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract ByteStream flatMapToByte(IntFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract ShortStream flatMapToShort(IntFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract LongStream flatMapToLong(IntFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract FloatStream flatMapToFloat(IntFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract DoubleStream flatMapToDouble(IntFunction mapper); /** * * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream flatMapToObj(IntFunction> mapper); /** * * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream flatmapToObj(IntFunction> mapper); //NOSONAR /** * * @param * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract Stream flattMapToObj(IntFunction mapper); /** * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract IntStream mapMulti(IntMapMultiConsumer mapper); /** * Note: copied from StreamEx: StreamEx * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract IntStream mapPartial(IntFunction mapper); /** * Note: copied from StreamEx: StreamEx * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract IntStream mapPartialJdk(IntFunction mapper); /** * Note: copied from StreamEx: 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 {@code 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(IntBiPredicate, IntBinaryOperator) * @see Stream#rangeMap(BiPredicate, BiFunction) */ @SequentialOnly @IntermediateOp public abstract IntStream rangeMap(final IntBiPredicate sameRange, final IntBinaryOperator mapper); /** * Note: copied from StreamEx: 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 * @param sameRange a non-interfering, stateless predicate to apply to * the leftmost and next elements which returns {@code 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 IntBiPredicate sameRange, final IntBiFunction mapper); /** * Merges a series of adjacent elements in the stream which satisfy the given predicate into a List. * The predicate takes two parameters: the previous element and the current element in the stream. * If the predicate returns {@code true}, the current element and its previous element are considered as a series of adjacent elements. * These elements are then collapsed into a List. * * This is an intermediate operation, meaning it's always lazy. It doesn't start processing the data until a terminal operation is invoked on the stream pipeline. * It's also a stateful operation since it needs to remember the previous element when processing the current element. * * This operation is not parallelizable and requires the stream to be ordered. * * @param collapsible a BiPredicate that takes two parameters: the previous element and the current element in the stream. * @return a new Stream where each element is a List of adjacent elements which satisfy the given predicate. * @see Stream#collapse(BiPredicate) */ @SequentialOnly @IntermediateOp public abstract Stream collapse(final IntBiPredicate collapsible); /** * Merges a series of adjacent elements in the stream which satisfy the given predicate using the merger function and returns a new stream. * The predicate takes two parameters: the previous element and the current element in the stream. * If the predicate returns {@code true}, the current element and its previous element are considered as a series of adjacent elements. * These elements are then merged using the provided BiFunction. * * This is an intermediate operation, meaning it's always lazy. It doesn't start processing the data until a terminal operation is invoked on the stream pipeline. * It's also a stateful operation since it needs to remember the previous element when processing the current element. * * This operation is not parallelizable and requires the stream to be ordered. * * @param collapsible a BiPredicate that takes two parameters: the previous element and the current element in the stream. * @param mergeFunction a BiFunction that takes two parameters: the result of the previous merge operation (or the first element if no merge has been performed yet) and the current element, and returns the result of the merge operation. * @return a new Stream where each element is the result of merging adjacent elements which satisfy the given predicate. * @see Stream#collapse(BiPredicate, BiFunction) */ @SequentialOnly @IntermediateOp public abstract IntStream collapse(final IntBiPredicate collapsible, final IntBinaryOperator mergeFunction); /** * Merges a series of adjacent elements in the stream which satisfy the given predicate into a single element and returns a new stream. * The predicate takes three parameters: the first element of the series, the previous element and the current element in the stream. * If the predicate returns {@code true}, the current element, its previous element and the first element of the series are considered as a series of adjacent elements. * These elements are then collapsed into a single element using the provided merge function. * * This is an intermediate operation, meaning it's always lazy. It doesn't start processing the data until a terminal operation is invoked on the stream pipeline. * It's also a stateful operation since it needs to remember the first and previous elements when processing the current element. * * This operation is not parallelizable and requires the stream to be ordered. * * @param collapsible a TriPredicate that takes three parameters: the first element of the series, the previous element and the current element in the stream. * @param mergeFunction a BiFunction that takes two parameters: the current element and its previous element. It returns a single element that represents the collapsed elements. * @return a new Stream where each element is the result of collapsing adjacent elements which satisfy the given predicate. * @see Stream#collapse(com.landawn.abacus.util.function.TriPredicate, BiFunction) */ @SequentialOnly @IntermediateOp public abstract IntStream collapse(final IntTriPredicate collapsible, final IntBinaryOperator mergeFunction); /** * Performs a scan (also known as prefix sum, cumulative sum, running total, or integral) operation on the elements of the stream. * The scan operation takes a binary operator (the accumulator) and applies it cumulatively on the stream elements, * successively combining each element in order from the start to produce a stream of accumulated results. * * For example, given a stream of numbers [1, 2, 3, 4], and an accumulator that performs addition, * the output would be a stream of numbers [1, 3, 6, 10]. * * This is an intermediate operation. * This operation is sequential only, even when called on a parallel stream. * * @param accumulator a {@code IntBinaryOperator} that takes two parameters: the current accumulated value and the current stream element, and returns a new accumulated value. * @return a new {@code IntStream} consisting of the results of the scan operation on the elements of the original stream. * @see Stream#scan(BiFunction) */ @SequentialOnly @IntermediateOp public abstract IntStream scan(final IntBinaryOperator accumulator); /** * Performs a scan (also known as prefix sum, cumulative sum, running total, or integral) operation on the elements of the stream. * The scan operation takes an initial value and a binary operator (the accumulator) and applies it cumulatively on the stream elements, * successively combining each element in order from the start to produce a stream of accumulated results. * * For example, given a stream of numbers [1, 2, 3, 4], an initial value of 10, and an accumulator that performs addition, * the output would be a stream of numbers [11, 13, 16, 20]. * This is an intermediate operation. * This operation is sequential only, even when called on a parallel stream. * * @param init the initial value. It's only used once by the accumulator to calculate the first 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 a {@code IntBinaryOperator} that takes two parameters: the current accumulated value and the current stream element, and returns a new accumulated value. * @return a new {@code IntStream} consisting of the results of the scan operation on the elements of the original stream. * @see Stream#scan(Object, BiFunction) */ @SequentialOnly @IntermediateOp public abstract IntStream scan(final int init, final IntBinaryOperator accumulator); /** * Performs a scan (also known as prefix sum, cumulative sum, running total, or integral) operation on the elements of the stream. * The scan operation takes an initial value and a binary operator (the accumulator) and applies it cumulatively on the stream elements, * successively combining each element in order from the start to produce a stream of accumulated results. * * This is an intermediate operation. * This operation is sequential only, even when called on a parallel stream. * * @param init the initial value. It's only used once by the accumulator to calculate the first element in the returned stream. * @param initIncluded a boolean value that determines if the initial value should be included as the first element in the returned stream. * @param accumulator a {@code IntBinaryOperator} that takes two parameters: the current accumulated value and the current stream element, and returns a new accumulated value. * @return a new {@code IntStream} consisting of the results of the scan operation on the elements of the original stream. * @see Stream#scan(Object, boolean, BiFunction) */ @SequentialOnly @IntermediateOp public abstract IntStream scan(final int init, final boolean initIncluded, final IntBinaryOperator accumulator); /** * * @param a * @return */ @SequentialOnly @IntermediateOp public abstract IntStream prepend(final int... a); /** * * @param a * @return */ @SequentialOnly @IntermediateOp public abstract IntStream append(final int... a); /** * * @param a * @return */ @SequentialOnly @IntermediateOp public abstract IntStream appendIfEmpty(final int... a); /** * *
* This method only runs sequentially, even in parallel stream. * * @param n * @return */ @SequentialOnly @IntermediateOp public abstract IntStream top(int n); /** * *
* This method only runs sequentially, even in parallel stream. * * @param n * @param comparator * @return */ @SequentialOnly @IntermediateOp public abstract IntStream top(final int n, Comparator comparator); @SequentialOnly @TerminalOp public abstract IntList toIntList(); /** * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @return * @throws E * @throws E2 * @see Collectors#toMap(Function, Function) */ @ParallelSupported @TerminalOp public abstract Map toMap(Throwables.IntFunction keyMapper, Throwables.IntFunction valueMapper) throws E, E2; /** * * @param * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return * @throws E * @throws E2 * @see Collectors#toMap(Function, Function, Supplier) */ @ParallelSupported @TerminalOp public abstract , E extends Exception, E2 extends Exception> M toMap(Throwables.IntFunction keyMapper, Throwables.IntFunction valueMapper, Supplier mapFactory) throws E, E2; /** * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return * @throws E * @throws E2 * @see Collectors#toMap(Function, Function, BinaryOperator) */ @ParallelSupported @TerminalOp public abstract Map toMap(Throwables.IntFunction keyMapper, Throwables.IntFunction valueMapper, BinaryOperator mergeFunction) throws E, E2; /** * * @param * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return * @throws E * @throws E2 * @see Collectors#toMap(Function, Function, BinaryOperator, Supplier) */ @ParallelSupported @TerminalOp public abstract , E extends Exception, E2 extends Exception> M toMap(Throwables.IntFunction keyMapper, Throwables.IntFunction valueMapper, BinaryOperator mergeFunction, Supplier mapFactory) throws E, E2; /** * * @param * @param * @param * @param keyMapper * @param downstream * @return * @throws E * @see Collectors#groupingBy(Function, Collector) */ @ParallelSupported @TerminalOp public abstract Map groupTo(Throwables.IntFunction keyMapper, final Collector downstream) throws E; /** * * @param * @param * @param * @param * @param keyMapper * @param downstream * @param mapFactory * @return * @throws E * @see Collectors#groupingBy(Function, Collector, Supplier) */ @ParallelSupported @TerminalOp public abstract , E extends Exception> M groupTo(Throwables.IntFunction keyMapper, final Collector downstream, final Supplier mapFactory) throws E; /** * Performs a reduction on the elements of this stream, using the provided accumulator function, and returns the reduced value. * The accumulator function takes two parameters: the current reduced value (or the initial value for the first element), and the current stream element. * * @param identity the initial value of the reduction operation * @param op the function for combining the current reduced value and the current stream element * @return the result of the reduction * @see Stream#reduce(Object, BinaryOperator) */ @ParallelSupported @TerminalOp public abstract int reduce(int identity, IntBinaryOperator op); /** * Performs a reduction on the elements of this stream, using the provided accumulator function, and returns the reduced value. * The accumulator function takes two parameters: the current reduced value and the current stream element. * * @param op the function for combining the current reduced value and the current stream element * @return an OptionalInt describing the result of the reduction. If the stream is empty, an empty OptionalInt is returned. * @see Stream#reduce(BinaryOperator) */ @ParallelSupported @TerminalOp public abstract OptionalInt reduce(IntBinaryOperator op); /** * Performs a mutable reduction operation on the elements of this stream using a Collector. * * @param The type of the result * @param supplier a function that creates a new result container. For a parallel execution, this function may be called multiple times and must return a fresh value each time. * @param accumulator an associative, non-interfering, stateless function for incorporating an additional element into a result * @param combiner an associative, non-interfering, stateless function for combining two values, which must be compatible with the accumulator function. * It's unnecessary to specify {@code combiner} if {@code R} is a {@code Map/Collection/StringBuilder/Multiset/LongMultiset/Multimap/BooleanList/IntList/.../DoubleList}. * @return the result of the reduction * @see Stream#collect(Supplier, BiConsumer, BiConsumer) * @see BiConsumers#ofAddAll() * @see BiConsumers#ofPutAll() */ @ParallelSupported @TerminalOp public abstract R collect(Supplier supplier, ObjIntConsumer accumulator, BiConsumer combiner); /** * Performs a mutable reduction operation on the elements of this stream using a Collector. * *
* Only call this method when the returned type {@code R} is one types: {@code Collection/Map/StringBuilder/Multiset/LongMultiset/Multimap/BooleanList/IntList/.../DoubleList}. * Otherwise, please call {@link #collect(Supplier, ObjIntConsumer, BiConsumer)}. * * @param The type of the result. It must be {@code Collection/Map/StringBuilder/Multiset/LongMultiset/Multimap/BooleanList/IntList/.../DoubleList}. * @param supplier A function that creates a new result container. For a parallel execution, this function may be called multiple times and must return a fresh value each time. * @param accumulator An associative, non-interfering, stateless function for incorporating an additional element into a result. * @throws IllegalArgumentException if the returned type {@code R} is not one of the types: {@code Collection/Map/StringBuilder/Multiset/LongMultiset/Multimap/BooleanList/IntList/.../DoubleList}. * @return the result of the reduction * @see #collect(Supplier, ObjIntConsumer, BiConsumer) * @see Stream#collect(Supplier, BiConsumer) * @see Stream#collect(Supplier, BiConsumer, BiConsumer) */ @ParallelSupported @TerminalOp public abstract R collect(Supplier supplier, ObjIntConsumer accumulator); /** * * @param action */ @ParallelSupported @TerminalOp public void foreach(final IntConsumer action) { // NOSONAR forEach(action::accept); } /** * * @param * @param action * @throws E */ @ParallelSupported @TerminalOp public abstract void forEach(final Throwables.IntConsumer action) throws E; //NOSONAR /** * * @param * @param action * @throws E */ @ParallelSupported @TerminalOp public abstract void forEachIndexed(Throwables.IntIntConsumer action) throws E; /** * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract boolean anyMatch(final Throwables.IntPredicate predicate) throws E; /** * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract boolean allMatch(final Throwables.IntPredicate predicate) throws E; /** * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract boolean noneMatch(final Throwables.IntPredicate predicate) throws E; /** * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract OptionalInt findFirst(final Throwables.IntPredicate predicate) throws E; /** * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract OptionalInt findAny(final Throwables.IntPredicate predicate) throws E; /** * Consider using: {@code stream.reversed().findFirst(predicate)} for better performance if possible. * * @param * @param predicate * @return * @throws E */ @Beta @ParallelSupported @TerminalOp public abstract OptionalInt findLast(final Throwables.IntPredicate predicate) throws E; // /** // * Returns the first element matched by {@code predicateForFirst} if found or the first element if this stream is not empty // * Otherwise an empty {@code OptionalInt} will be returned. // * // * @param // * @param predicateForFirst // * @return // * @throws E // */ // @ParallelSupported // @TerminalOp // public abstract OptionalInt findFirstOrElseAny(Throwables.IntPredicate predicateForFirst) throws E; // // /** // * Returns the first element matched by {@code predicateForFirst} if found or the last element if this stream is not empty // * Otherwise an empty {@code OptionalInt} will be returned. // * // * @param // * @param predicateForFirst // * @return // * @throws E // */ // @ParallelSupported // @TerminalOp // public abstract OptionalInt findFirstOrElseLast(Throwables.IntPredicate predicateForFirst) throws E; @SequentialOnly @TerminalOp public abstract OptionalInt min(); @SequentialOnly @TerminalOp public abstract OptionalInt max(); /** * Returns the k-th largest element in the stream. * If the stream is empty or the count of elements is less than k, an empty OptionalInt is returned. * * @param k the position (1-based) of the largest element to retrieve * @return an OptionalInt containing the k-th largest element, or an empty OptionalInt if the stream is empty or the count of elements is less than k */ @SequentialOnly @TerminalOp public abstract OptionalInt kthLargest(int k); @SequentialOnly @TerminalOp public abstract int sum(); @SequentialOnly @TerminalOp public abstract OptionalDouble average(); @SequentialOnly @TerminalOp public abstract IntSummaryStatistics summarize(); @SequentialOnly @TerminalOp public abstract Pair>> summarizeAndPercentiles(); // /** // * // * @param b // * @param nextSelector a function to determine which element should be selected as next element. // * The first parameter is selected if {@code MergeResult.TAKE_FIRST} is returned, otherwise the second parameter is selected. // * @return // * @deprecated replaced by {@code mergeWith(IntStream, IntBiFunction)} // * @see #mergeWith(IntStream, IntBiFunction) // */ // @SequentialOnly // @IntermediateOp // @Deprecated // public IntStream merge(final IntStream b, final IntBiFunction nextSelector) { // return mergeWith(b, nextSelector); // } /** * * @param b * @param nextSelector a function to determine which element should be selected as next element. * The first parameter is selected if {@code MergeResult.TAKE_FIRST} is returned, otherwise the second parameter is selected. * @return */ @SequentialOnly @IntermediateOp public abstract IntStream mergeWith(final IntStream b, final IntBiFunction nextSelector); /** * * @param b * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract IntStream zipWith(IntStream b, IntBinaryOperator zipFunction); /** * * @param b * @param c * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract IntStream zipWith(IntStream b, IntStream c, IntTernaryOperator zipFunction); /** * * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract IntStream zipWith(IntStream b, int valueForNoneA, int valueForNoneB, IntBinaryOperator zipFunction); /** * * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract IntStream zipWith(IntStream b, IntStream c, int valueForNoneA, int valueForNoneB, int valueForNoneC, IntTernaryOperator zipFunction); @SequentialOnly @IntermediateOp public abstract LongStream asLongStream(); @SequentialOnly @IntermediateOp public abstract FloatStream asFloatStream(); @SequentialOnly @IntermediateOp public abstract DoubleStream asDoubleStream(); // No performance improvement. // /** // * Temporarily switch the stream to Jdk parallel stream for operation {@code ops} and then switch back to sequence stream. // *
// * {@code stream.(switchToJdkStream).parallel().ops(map/filter/...).(switchBack).sequence()} // * // * @param // * @param op // * @return // */ // @Beta // @IntermediateOp // public IntStream sjps(Function op) { // if (this.isParallel()) { // return of(op.apply(this.toJdkStream())).sequential(); // } else { // return of(op.apply(this.toJdkStream().parallel())); // } // } @SequentialOnly @IntermediateOp public abstract Stream boxed(); @SequentialOnly @IntermediateOp public abstract java.util.stream.IntStream toJdkStream(); /** * * @param transfer * @return */ @Beta @SequentialOnly @IntermediateOp public IntStream transformB(final Function transfer) { return transformB(transfer, false); } /** * * @param transfer * @param deferred * @return * @throws IllegalArgumentException */ @Beta @SequentialOnly @IntermediateOp public IntStream transformB(final Function transfer, final boolean deferred) throws IllegalArgumentException { assertNotClosed(); checkArgNotNull(transfer, cs.transfer); if (deferred) { final Supplier delayInitializer = () -> IntStream.from(transfer.apply(toJdkStream())); return IntStream.defer(delayInitializer); } else { return IntStream.from(transfer.apply(toJdkStream())); } } abstract IntIteratorEx iteratorEx(); // private static final IntStream EMPTY_STREAM = new ArrayIntStream(N.EMPTY_INT_ARRAY, true, null); /** * Returns an empty IntStream. * * @return an empty IntStream */ public static IntStream empty() { return new ArrayIntStream(N.EMPTY_INT_ARRAY, true, null); } /** * Creates a new IntStream that is supplied by the given supplier. * The supplier is only invoked when the stream is actually used. * This allows for lazy evaluation of the stream. * * @implNote it's equivalent to {@code Stream.just(supplier).flatMapToInt(it -> it.get())}. * * @param supplier the supplier that provides the IntStream * @return a new IntStream supplied by the given supplier * @throws IllegalArgumentException if the supplier is null * @see Stream#defer(Supplier) */ public static IntStream defer(final Supplier supplier) throws IllegalArgumentException { N.checkArgNotNull(supplier, cs.supplier); //noinspection resource return Stream.just(supplier).flatMapToInt(Supplier::get); } /** * * @param stream * @return */ public static IntStream from(final java.util.stream.IntStream stream) { if (stream == null) { return empty(); } return of(new IntIteratorEx() { private PrimitiveIterator.OfInt iter = null; @Override public boolean hasNext() { if (iter == null) { iter = stream.iterator(); } return iter.hasNext(); } @Override public int nextInt() { if (iter == null) { iter = stream.iterator(); } return iter.nextInt(); } @Override public long count() { return iter == null ? stream.count() : super.count(); } @Override public void advance(final long n) { if (iter == null) { iter = stream.skip(n).iterator(); } else { super.advance(n); } } @Override public int[] toArray() { return iter == null ? stream.toArray() : super.toArray(); } }).transform(s -> stream.isParallel() ? s.parallel() : s.sequential()).onClose(stream::close); } /** * * @param e * @return */ public static IntStream ofNullable(final Integer e) { return e == null ? empty() : of(e); } /** * * @param a * @return */ @SafeVarargs public static IntStream of(final int... a) { return N.isEmpty(a) ? empty() : new ArrayIntStream(a); } /** * * @param a * @param startIndex * @param endIndex * @return */ public static IntStream of(final int[] a, final int startIndex, final int endIndex) { return N.isEmpty(a) && (startIndex == 0 && endIndex == 0) ? empty() : new ArrayIntStream(a, startIndex, endIndex); } /** * * @param a * @return */ public static IntStream of(final Integer[] a) { //noinspection resource return Stream.of(a).mapToInt(FI.unbox()); } /** * * @param a * @param startIndex * @param endIndex * @return */ public static IntStream of(final Integer[] a, final int startIndex, final int endIndex) { //noinspection resource return Stream.of(a, startIndex, endIndex).mapToInt(FI.unbox()); } /** * * @param c * @return */ public static IntStream of(final Collection c) { //noinspection resource return Stream.of(c).mapToInt(FI.unbox()); } /** * * @param iterator * @return */ public static IntStream of(final IntIterator iterator) { return iterator == null ? empty() : new IteratorIntStream(iterator); } /** * * @param stream * @return * @deprecated Use {@link #from(java.util.stream.IntStream)} instead */ // Should the name be from? @Deprecated public static IntStream of(final java.util.stream.IntStream stream) { return from(stream); } /** * * @param op * @return */ public static IntStream of(final OptionalInt op) { return op == null || op.isEmpty() ? IntStream.empty() : IntStream.of(op.get()); } /** * * @param op * @return */ public static IntStream of(final java.util.OptionalInt op) { return op == null || op.isEmpty() ? IntStream.empty() : IntStream.of(op.getAsInt()); } /** * * @param buf * @return */ public static IntStream of(final IntBuffer buf) { if (buf == null) { return empty(); } //noinspection resource return range(buf.position(), buf.limit()).map(buf::get); } /** * * @param str * @return */ public static IntStream ofCodePoints(final CharSequence str) { if (Strings.isEmpty(str)) { return empty(); } // final IntIterator iter = new IntIterator() { // private final int len = str.length(); // private int cursor = 0; // private char c1 = 0; // private char c2 = 0; // // @Override // public boolean hasNext() { // return cursor < len; // } // // @Override // public int nextInt() { // if (cursor >= len) { // throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); // } // // c1 = str.charAt(cursor++); // // if (Character.isHighSurrogate(c1) && cursor < len) { // c2 = str.charAt(cursor); // // if (Character.isLowSurrogate(c2)) { // cursor++; // return Character.toCodePoint(c1, c2); // } // } // // return c1; // } // }; // // return of(iter); return from(str.codePoints()); } private static final Function flatMapper = IntStream::of; private static final Function flattMapper = IntStream::flatten; /** * Splits the total size into chunks based on the specified maximum chunk count. *
* The size of the chunks is larger first. *
* The length of returned IntStream may be less than the specified {@code maxChunkCount} if the input {@code totalSize} is less than {@code maxChunkCount}. * * @param totalSize the total size to be split. It could be the size of an array, list, etc. * @param maxChunkCount the maximum number of chunks to split into * @param mapper a function to map the chunk from and to index to an element in the resulting stream * @return an IntStream of the mapped chunk values * @throws IllegalArgumentException if {@code totalSize} is negative or {@code maxChunkCount} is not positive. * @see #splitByChunkCount(int, int, boolean, IntBinaryOperator) */ public static IntStream splitByChunkCount(final int totalSize, final int maxChunkCount, final IntBinaryOperator mapper) { return splitByChunkCount(totalSize, maxChunkCount, false, mapper); } /** * Splits the total size into chunks based on the specified maximum chunk count. *
* The size of the chunks can be either smaller or larger first based on the flag. *
* The length of returned IntStream may be less than the specified {@code maxChunkCount} if the input {@code totalSize} is less than {@code maxChunkCount}. * *
     * 
     * final int[] a = Array.rangeClosed(1, 7);
     * splitByChunkCount(7, 5, true, (fromIndex, toIndex) ->  copyOfRange(a, fromIndex, toIndex)); // [[1], [2], [3], [4, 5], [6, 7]]
     * splitByChunkCount(7, 5, false, (fromIndex, toIndex) ->  copyOfRange(a, fromIndex, toIndex)); // [[1, 2], [3, 4], [5], [6], [7]]
     * 
     * 
* * @param totalSize the total size to be split. It could be the size of an array, list, etc. * @param maxChunkCount the maximum number of chunks to split into * @param sizeSmallerFirst if {@code true}, smaller chunks will be created first; otherwise, larger chunks will be created first * @param mapper a function to map the chunk from and to index to an element in the resulting stream * @return an IntStream of the mapped chunk values * @throws IllegalArgumentException if {@code totalSize} is negative or {@code maxChunkCount} is not positive. * @see Stream#splitByChunkCount(int, int, boolean, IntBiFunction) */ public static IntStream splitByChunkCount(final int totalSize, final int maxChunkCount, final boolean sizeSmallerFirst, final IntBinaryOperator mapper) { N.checkArgNotNegative(totalSize, cs.totalSize); N.checkArgPositive(maxChunkCount, cs.maxChunkCount); if (totalSize == 0) { return IntStream.empty(); } final int count = Math.min(totalSize, maxChunkCount); final int biggerSize = totalSize % maxChunkCount == 0 ? totalSize / maxChunkCount : totalSize / maxChunkCount + 1; final int biggerCount = totalSize % maxChunkCount; final int smallerSize = Math.max(totalSize / maxChunkCount, 1); final int smallerCount = count - biggerCount; IntIterator iter = null; if (sizeSmallerFirst) { iter = new IntIteratorEx() { private int cnt = 0; private int cursor = 0; @Override public boolean hasNext() { return cursor < totalSize; } @Override public int nextInt() { if (cursor >= totalSize) { throw new NoSuchElementException(InternalUtil.ERROR_MSG_FOR_NO_SUCH_EX); } return mapper.applyAsInt(cursor, cursor = (cnt++ < smallerCount ? cursor + smallerSize : cursor + biggerSize)); } @Override public void advance(long n) throws IllegalArgumentException { if (n > 0) { while (n-- > 0 && cursor < totalSize) { cursor = cnt++ < smallerCount ? cursor + smallerSize : cursor + biggerSize; } } } @Override public long count() { return count; } }; } else { iter = new IntIteratorEx() { private int cnt = 0; private int cursor = 0; @Override public boolean hasNext() { return cursor < totalSize; } @Override public int nextInt() { if (cursor >= totalSize) { throw new NoSuchElementException(InternalUtil.ERROR_MSG_FOR_NO_SUCH_EX); } return mapper.applyAsInt(cursor, cursor = (cnt++ < biggerCount ? cursor + biggerSize : cursor + smallerSize)); } @Override public void advance(long n) throws IllegalArgumentException { if (n > 0) { while (n-- > 0 && cursor < totalSize) { cursor = cnt++ < biggerCount ? cursor + biggerSize : cursor + smallerSize; } } } @Override public long count() { return count; } }; } return IntStream.of(iter); } /** * * @param a * @return */ public static IntStream flatten(final int[][] a) { //noinspection resource return N.isEmpty(a) ? empty() : Stream.of(a).flatMapToInt(flatMapper); } /** * * @param a * @param vertically * @return */ public static IntStream flatten(final int[][] a, final boolean vertically) { if (N.isEmpty(a)) { return empty(); } else if (a.length == 1) { return of(a[0]); } else if (!vertically) { //noinspection resource return Stream.of(a).flatMapToInt(flatMapper); } long n = 0; for (final int[] e : a) { n += N.len(e); } if (n == 0) { return empty(); } final int rows = N.len(a); final long count = n; final IntIterator iter = new IntIteratorEx() { private int rowNum = 0; private int colNum = 0; private long cnt = 0; @Override public boolean hasNext() { return cnt < count; } @Override public int nextInt() { if (cnt++ >= count) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } 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); } /** * * @param a * @param valueForAlignment element to append so there are same size of elements in all rows/columns * @param vertically * @return */ public static IntStream flatten(final int[][] a, final int valueForAlignment, final boolean vertically) { if (N.isEmpty(a)) { return empty(); } else if (a.length == 1) { return of(a[0]); } long n = 0; int maxLen = 0; for (final int[] 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 = (long) rows * cols; IntIterator iter = null; if (vertically) { iter = new IntIteratorEx() { private int rowNum = 0; private int colNum = 0; private long cnt = 0; @Override public boolean hasNext() { return cnt < count; } @Override public int nextInt() { if (cnt++ >= count) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } if (rowNum == rows) { rowNum = 0; colNum++; } if (a[rowNum] == null || colNum >= a[rowNum].length) { rowNum++; return valueForAlignment; } else { return a[rowNum++][colNum]; } } }; } else { iter = new IntIteratorEx() { private int rowNum = 0; private int colNum = 0; private long cnt = 0; @Override public boolean hasNext() { return cnt < count; } @Override public int nextInt() { if (cnt++ >= count) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } if (colNum >= cols) { colNum = 0; rowNum++; } if (a[rowNum] == null || colNum >= a[rowNum].length) { colNum++; return valueForAlignment; } else { return a[rowNum][colNum++]; } } }; } return of(iter); } /** * * @param a * @return */ public static IntStream flatten(final int[][][] a) { //noinspection resource return N.isEmpty(a) ? empty() : Stream.of(a).flatMapToInt(flattMapper); } /** * * @param startInclusive * @param endExclusive * @return */ public static IntStream range(final int startInclusive, final int endExclusive) { if (startInclusive >= endExclusive) { return empty(); } return new IteratorIntStream(new IntIteratorEx() { private int next = startInclusive; private long cnt = (long) endExclusive - startInclusive; @Override public boolean hasNext() { return cnt > 0; } @Override public int nextInt() { if (cnt-- <= 0) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } return next++; } @Override public void advance(final long n) { cnt = n >= cnt ? 0 : cnt - (int) n; next += (int) n; } @Override public long count() { return cnt; } @Override public int[] toArray() { final int[] result = new int[(int) cnt]; for (int i = 0; i < cnt; i++) { result[i] = next++; } cnt = 0; return result; } }); } /** * * @param startInclusive * @param endExclusive * @param by * @return */ public static IntStream range(final int startInclusive, final int endExclusive, final int by) { if (by == 0) { throw new IllegalArgumentException("'by' can't be zero"); } if (endExclusive == startInclusive || endExclusive > startInclusive != by > 0) { return empty(); } return new IteratorIntStream(new IntIteratorEx() { private int next = startInclusive; private long cnt = ((long) endExclusive - startInclusive) / by + (((long) endExclusive - startInclusive) % by == 0 ? 0 : 1); @Override public boolean hasNext() { return cnt > 0; } @Override public int nextInt() { if (cnt-- <= 0) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } final int result = next; next += by; return result; } @Override public void advance(final long n) { cnt = n >= cnt ? 0 : cnt - (int) n; next += (int) (n * by); } @Override public long count() { return cnt; } @Override public int[] toArray() { final int[] result = new int[(int) cnt]; for (int i = 0; i < cnt; i++, next += by) { result[i] = next; } cnt = 0; return result; } }); } /** * * @param startInclusive * @param endInclusive * @return */ public static IntStream rangeClosed(final int startInclusive, final int endInclusive) { if (startInclusive > endInclusive) { return empty(); } else if (startInclusive == endInclusive) { return of(startInclusive); } return new IteratorIntStream(new IntIteratorEx() { private int next = startInclusive; private long cnt = (long) endInclusive - startInclusive + 1; @Override public boolean hasNext() { return cnt > 0; } @Override public int nextInt() { if (cnt-- <= 0) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } return next++; } @Override public void advance(final long n) { cnt = n >= cnt ? 0 : cnt - (int) n; next += (int) n; } @Override public long count() { return cnt; } @Override public int[] toArray() { final int[] result = new int[(int) cnt]; for (int i = 0; i < cnt; i++) { result[i] = next++; } cnt = 0; return result; } }); } /** * * @param startInclusive * @param endInclusive * @param by * @return */ public static IntStream rangeClosed(final int startInclusive, final int endInclusive, final int 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(); } return new IteratorIntStream(new IntIteratorEx() { private int next = startInclusive; private long cnt = ((long) endInclusive - startInclusive) / by + 1; @Override public boolean hasNext() { return cnt > 0; } @Override public int nextInt() { if (cnt-- <= 0) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } final int result = next; next += by; return result; } @Override public void advance(final long n) { cnt = n >= cnt ? 0 : cnt - (int) n; next += (int) (n * by); } @Override public long count() { return cnt; } @Override public int[] toArray() { final int[] result = new int[(int) cnt]; for (int i = 0; i < cnt; i++, next += by) { result[i] = next; } cnt = 0; return result; } }); } /** * * @param element * @param n * @return * @throws IllegalArgumentException */ public static IntStream repeat(final int element, final long n) throws IllegalArgumentException { N.checkArgNotNegative(n, cs.n); if (n == 0) { return empty(); } else if (n < 10) { return of(Array.repeat(element, (int) n)); } return new IteratorIntStream(new IntIteratorEx() { private long cnt = n; @Override public boolean hasNext() { return cnt > 0; } @Override public int nextInt() { if (cnt-- <= 0) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } return element; } @Override public void advance(final long n) { cnt = n >= cnt ? 0 : cnt - (int) n; } @Override public long count() { return cnt; } @Override public int[] toArray() { final int[] result = new int[(int) cnt]; for (int i = 0; i < cnt; i++) { result[i] = element; } cnt = 0; return result; } }); } public static IntStream random() { return generate(RAND::nextInt); } /** * * @param startInclusive * @param endExclusive * @return */ public static IntStream random(final int startInclusive, final int endExclusive) { if (startInclusive >= endExclusive) { throw new IllegalArgumentException("'startInclusive' must be less than 'endExclusive'"); } final long mod = (long) endExclusive - (long) startInclusive; if (mod < Integer.MAX_VALUE) { final int n = (int) mod; return generate(() -> RAND.nextInt(n) + startInclusive); } else { return generate(() -> (int) (Math.abs(RAND.nextLong() % mod) + startInclusive)); } } /** * Creates an IntStream of indices from 0 (inclusive) to the specified length or size (exclusive). * * @param lenOrSize the length or size of a collection, map, array, CharSequence, etc. * @return an IntStream of indices from 0 to lenOrSize (exclusive) * @throws IllegalArgumentException if lenOrSize is negative * @see N#len(CharSequence) * @see N#len(int[]) * @see N#len(Object[]) * @see N#size(Collection) * @see N#size(Map) * @see N#forEach(int, int, Throwables.IntConsumer) */ @Beta public static IntStream ofIndices(final int lenOrSize) { N.checkArgNotNegative(lenOrSize, cs.lenOrSize); return range(0, lenOrSize); } /** * Creates an IntStream of indices from 0 to {@code lenOrSize} (exclusive) with the specified step when {@code step} is positive, * or from {@code lenOrSize} - 1 to 0 (inclusive) with the specified {@code step} when step is negative. * * @param lenOrSize the length or size of a collection, map, array, CharSequence, etc. * @param step the increment value for each iteration in the range. It can be positive or negative but not zero. * @return an IntStream of indices from 0 to lenOrSize (exclusive) with the specified step when step is positive, or from lenOrSize - 1 to 0 (inclusive) with the specified step when step is negative. * @throws IllegalArgumentException if lenOrSize is negative, or if step is zero. * @see N#len(CharSequence) * @see N#len(int[]) * @see N#len(Object[]) * @see N#size(Collection) * @see N#size(Map) * @see N#forEach(int, int, int, Throwables.IntConsumer) */ @Beta public static IntStream ofIndices(final int lenOrSize, final int step) { N.checkArgNotNegative(lenOrSize, cs.lenOrSize); N.checkArgument(step != 0, "The input parameter 'step' can not be zero"); if (step == 1) { return range(0, lenOrSize); } else if (step < 0) { return range(lenOrSize - 1, -1, step); } else { return range(0, lenOrSize, step); } } /** * Creates an IntStream of indices from the given source using the provided index function. * * @param the type of the source. It should be {@code array}, {@code Collection} or {@code CharSequence}. * @param source the source from which indices are generated * @param indexFunc the function to generate indices from the source * @return an IntStream of indices */ @Beta public static IntStream ofIndices(final AC source, final ObjIntFunction indexFunc) { return ofIndices(source, 0, indexFunc); } /** * Creates an IntStream of indices from the given source starting from the specified index using the provided index function. * * @param the type of the source. It should be {@code array}, {@code Collection} or {@code CharSequence}. * @param source the source from which indices are generated * @param fromIndex the starting index from which to generate indices * @param indexFunc the function to generate indices from the source * @return an IntStream of indices */ @Beta public static IntStream ofIndices(final AC source, final int fromIndex, final ObjIntFunction indexFunc) { return ofIndices(source, fromIndex, 1, indexFunc); } /** * Creates an IntStream of indices from the given source using the provided index function. * *
     * 
     * // Forwards:
     * int[] source = { 1, 2, 3, 1, 5, 1};
     * IntStream.ofIndices(source, (a, fromIndex) -> N.indexOf(a, 1, fromIndex)).println(); // [0, 3, 5]
     * IntStream.ofIndices(source, 1, (a, fromIndex) -> N.indexOf(a, 1, fromIndex)).println(); // [3, 5]
     *
     * // Backwards
     * IntStream.ofIndices(source, 5, -1, (a, fromIndex) -> N.lastIndexOf(a, 1, fromIndex)).println(); // [5, 3, 0]
     * IntStream.ofIndices(source, 4, -1, (a, fromIndex) -> N.lastIndexOf(a, 1, fromIndex)).println(); // [3, 0]
     *
     * 
     * 
* * @param the type of the source. It should be {@code array}, {@code Collection} or {@code CharSequence}. * @param source * @param fromIndex * @param increment * @param indexFunc * @return */ @Beta public static IntStream ofIndices(final AC source, final int fromIndex, final int increment, final ObjIntFunction indexFunc) { @SuppressWarnings("rawtypes") final int sourceLen = source.getClass().isArray() ? Array.getLength(source) : (source instanceof Collection ? ((Collection) source).size() : (source instanceof CharSequence ? ((CharSequence) source).length() : Integer.MAX_VALUE)); return ofIndices(source, fromIndex, increment, sourceLen, indexFunc); } /** * Creates an IntStream of indices from the given source using the provided index function. * * @param the type of the source. It should be {@code array}, {@code Collection} or {@code CharSequence}. * @param source the source from which indices are generated * @param fromIndex the starting index from which to generate indices * @param increment the increment value for generating indices * @param sourceLen the length of the source * @param indexFunc the function to generate indices from the source * @return an IntStream of indices * @throws IllegalArgumentException if the increment is zero or if the source is null */ @Beta public static IntStream ofIndices(final AC source, final int fromIndex, final int increment, final int sourceLen, final ObjIntFunction indexFunc) throws IllegalArgumentException { N.checkArgNotNegative(fromIndex, cs.fromIndex); N.checkArgument(increment != 0, "'increment' can't be zero"); N.checkArgNotNull(indexFunc, cs.indexFunc); if (source == null) { return IntStream.empty(); } final IntUnaryOperator f = idx -> ((increment > 0 && idx >= sourceLen - increment) || (increment < 0 && idx + increment < 0)) ? N.INDEX_NOT_FOUND : indexFunc.apply(source, idx + increment); return iterate(indexFunc.apply(source, fromIndex), com.landawn.abacus.util.function.IntPredicate.NOT_NEGATIVE, f); } /** * Creates a stream that iterates using the given hasNext and next suppliers. * * @param hasNext a BooleanSupplier that returns {@code true} if the iteration should continue * @param next a IntSupplier that provides the next int in the iteration * @return a IntStream of elements generated by the iteration * @throws IllegalArgumentException if hasNext or next is null * @see Stream#iterate(BooleanSupplier, Supplier) */ public static IntStream iterate(final BooleanSupplier hasNext, final IntSupplier next) throws IllegalArgumentException { N.checkArgNotNull(hasNext); N.checkArgNotNull(next); return new IteratorIntStream(new IntIteratorEx() { private boolean hasNextVal = false; @Override public boolean hasNext() { if (!hasNextVal) { hasNextVal = hasNext.getAsBoolean(); } return hasNextVal; } @Override public int nextInt() { if (!hasNextVal && !hasNext()) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } hasNextVal = false; return next.getAsInt(); } }); } /** * Creates a stream that iterates from an initial value, applying a function to generate subsequent values, * and continues as long as a predicate is satisfied. * * @param init the initial value * @param hasNext a BooleanSupplier that returns {@code true} if the iteration should continue * @param f a function to apply to the previous element to generate the next element * @return a IntStream of elements generated by the iteration * @throws IllegalArgumentException if hasNext or f is null * @see Stream#iterate(Object, BooleanSupplier, java.util.function.UnaryOperator) */ public static IntStream iterate(final int init, final BooleanSupplier hasNext, final IntUnaryOperator f) throws IllegalArgumentException { N.checkArgNotNull(hasNext); N.checkArgNotNull(f); return new IteratorIntStream(new IntIteratorEx() { private int cur = 0; private boolean isFirst = true; private boolean hasNextVal = false; @Override public boolean hasNext() { if (!hasNextVal) { hasNextVal = hasNext.getAsBoolean(); } return hasNextVal; } @Override public int nextInt() { if (!hasNextVal && !hasNext()) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } hasNextVal = false; if (isFirst) { isFirst = false; cur = init; } else { cur = f.applyAsInt(cur); } return cur; } }); } /** * Creates a stream that iterates from an initial value, applying a function to generate subsequent values, * and continues as long as a predicate is satisfied. * * @param init the initial value * @param hasNext determinate if the returned stream has next by hasNext.test(init) for first time and hasNext.test(f.apply(previous)) for remaining. * @param f a function to apply to the previous element to generate the next element * @return a IntStream of elements generated by the iteration * @throws IllegalArgumentException if hasNext or f is null * @see Stream#iterate(Object, java.util.function.Predicate, java.util.function.UnaryOperator) */ public static IntStream iterate(final int init, final IntPredicate hasNext, final IntUnaryOperator f) throws IllegalArgumentException { N.checkArgNotNull(hasNext); N.checkArgNotNull(f); return new IteratorIntStream(new IntIteratorEx() { private int 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.applyAsInt(cur)); } if (!hasNextVal) { hasMore = false; } } return hasNextVal; } @Override public int nextInt() { if (!hasNextVal && !hasNext()) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } hasNextVal = false; return cur; } }); } /** * Creates a stream that iterates from an initial value, applying a function to generate subsequent values. * * @param init the initial value * @param f a function to apply to the previous element to generate the next element * @return a IntStream of elements generated by the iteration * @throws IllegalArgumentException if f is null * @see Stream#iterate(Object, java.util.function.UnaryOperator) */ public static IntStream iterate(final int init, final IntUnaryOperator f) throws IllegalArgumentException { N.checkArgNotNull(f); return new IteratorIntStream(new IntIteratorEx() { private int cur = 0; private boolean isFirst = true; @Override public boolean hasNext() { return true; } @Override public int nextInt() { if (isFirst) { isFirst = false; cur = init; } else { cur = f.applyAsInt(cur); } return cur; } }); } /** * Generates a IntStream using the provided IntSupplier. * The supplier is used to generate each element of the stream. * * @param s the IntSupplier that provides the elements of the stream * @return a IntStream generated by the given supplier * @throws IllegalArgumentException if the supplier is null * @see Stream#generate(Supplier) */ public static IntStream generate(final IntSupplier s) throws IllegalArgumentException { N.checkArgNotNull(s); return new IteratorIntStream(new IntIteratorEx() { @Override public boolean hasNext() { return true; } @Override public int nextInt() { return s.getAsInt(); } }); } /** * Concatenates multiple arrays of ints into a single IntStream. * * @param a the arrays of ints to concatenate * @return a IntStream containing all the ints from the input arrays * @see Stream#concat(Object[][]) */ @SafeVarargs public static IntStream concat(final int[]... a) { if (N.isEmpty(a)) { return empty(); } return concat(Arrays.asList(a)); } /** * Concatenates multiple IntIterators into a single IntStream. * * @param a the arrays of IntIterator to concatenate * @return a IntStream containing all the ints from the input IntIterators * @see Stream#concat(Iterator[]) */ @SafeVarargs public static IntStream concat(final IntIterator... a) { if (N.isEmpty(a)) { return empty(); } return concatIterators(Array.asList(a)); } /** * Concatenates multiple IntStreams into a single IntStream. * * @param a the arrays of IntStream to concatenate * @return a IntStream containing all the ints from the input IntStreams * @see Stream#concat(Stream[]) */ @SafeVarargs public static IntStream concat(final IntStream... a) { if (N.isEmpty(a)) { return empty(); } return concat(Array.asList(a)); } /** * Concatenates a list of int array into a single IntStream. * * @param c the list of int array to concatenate * @return a IntStream containing all the ints from the input list of int array * @see Stream#concat(Object[][]) */ @Beta public static IntStream concat(final List c) { if (N.isEmpty(c)) { return empty(); } return of(new IntIteratorEx() { private final Iterator iter = c.iterator(); private int[] cur; private int cursor = 0; @Override public boolean hasNext() { while ((N.isEmpty(cur) || cursor >= cur.length) && iter.hasNext()) { cur = iter.next(); cursor = 0; } return cur != null && cursor < cur.length; } @Override public int nextInt() { if ((cur == null || cursor >= cur.length) && !hasNext()) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } return cur[cursor++]; } }); } /** * Concatenates a collection of IntStream into a single IntStream. * * @param streams the collection of IntStream to concatenate * @return a IntStream containing all the ints from the input collection of IntStream * @see Stream#concat(Collection) */ public static IntStream concat(final Collection streams) { return N.isEmpty(streams) ? empty() : new IteratorIntStream(new IntIteratorEx() { //NOSONAR private final Iterator iterators = streams.iterator(); private IntStream cur; private IntIterator 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 int nextInt() { if ((iter == null || !iter.hasNext()) && !hasNext()) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } return iter.nextInt(); } }).onClose(newCloseHandler(streams)); } /** * Concatenates a collection of IntIterator into a single IntStream. * * @param intIterators the collection of IntIterator to concatenate * @return a IntStream containing all the ints from the input collection of IntIterator * @see Stream#concatIterators(Collection) */ @Beta public static IntStream concatIterators(final Collection intIterators) { if (N.isEmpty(intIterators)) { return empty(); } return new IteratorIntStream(new IntIteratorEx() { private final Iterator iter = intIterators.iterator(); private IntIterator cur; @Override public boolean hasNext() { while ((cur == null || !cur.hasNext()) && iter.hasNext()) { cur = iter.next(); } return cur != null && cur.hasNext(); } @Override public int nextInt() { if ((cur == null || !cur.hasNext()) && !hasNext()) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } return cur.nextInt(); } }); } /** * Zips two int arrays into a single IntStream until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction. * * @param a the first int array * @param b the second int array * @param zipFunction the function to combine elements from both arrays * @return a IntStream containing the results of applying the zip function to the elements of the input arrays * @see Stream#zip(Object[], Object[], BiFunction) */ public static IntStream zip(final int[] a, final int[] b, final IntBinaryOperator zipFunction) { if (N.isEmpty(a) || N.isEmpty(b)) { return empty(); } return new IteratorIntStream(new IntIteratorEx() { 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 int nextInt() { if (cursor >= len) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } return zipFunction.applyAsInt(a[cursor], b[cursor++]); } }); } /** * Zips three int arrays into a single IntStream until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction. * * @param a the first int array * @param b the second int array * @param c the third int array * @param zipFunction the function to combine elements from all three arrays * @return a IntStream containing the results of applying the zip function to the elements of the input arrays * @see Stream#zip(Object[], Object[], Object[], TriFunction) */ public static IntStream zip(final int[] a, final int[] b, final int[] c, final IntTernaryOperator zipFunction) { if (N.isEmpty(a) || N.isEmpty(b) || N.isEmpty(c)) { return empty(); } return new IteratorIntStream(new IntIteratorEx() { 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 int nextInt() { if (cursor >= len) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } return zipFunction.applyAsInt(a[cursor], b[cursor], c[cursor++]); } }); } /** * Zips two IntIterators into a single IntStream until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction. * * @param a the first IntIterator * @param b the second IntIterator * @param zipFunction the function to combine elements from both iterators * @return a IntStream containing the results of applying the zip function to the elements of the input iterators * @see Stream#zip(Iterator, Iterator, BiFunction) */ public static IntStream zip(final IntIterator a, final IntIterator b, final IntBinaryOperator zipFunction) { return new IteratorIntStream(new IntIteratorEx() { private final IntIterator iterA = a == null ? IntIterator.empty() : a; private final IntIterator iterB = b == null ? IntIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext(); } @Override public int nextInt() { return zipFunction.applyAsInt(iterA.nextInt(), iterB.nextInt()); } }); } /** * Zips three IntIterators into a single IntStream until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction. * * @param a the first IntIterator * @param b the second IntIterator * @param c the third IntIterator * @param zipFunction the function to combine elements from all three iterators * @return a IntStream containing the results of applying the zip function to the elements of the input iterators * @see Stream#zip(Iterator, Iterator, Iterator, TriFunction) */ public static IntStream zip(final IntIterator a, final IntIterator b, final IntIterator c, final IntTernaryOperator zipFunction) { return new IteratorIntStream(new IntIteratorEx() { private final IntIterator iterA = a == null ? IntIterator.empty() : a; private final IntIterator iterB = b == null ? IntIterator.empty() : b; private final IntIterator iterC = c == null ? IntIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public int nextInt() { return zipFunction.applyAsInt(iterA.nextInt(), iterB.nextInt(), iterC.nextInt()); } }); } /** * Zips two IntStreams into a single IntStream until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction. * * @param a the first IntStream * @param b the second IntStream * @param zipFunction the function to combine elements from both streams * @return a IntStream containing the results of applying the zip function to the elements of the input streams * @see Stream#zip(Stream, Stream, BiFunction) */ public static IntStream zip(final IntStream a, final IntStream b, final IntBinaryOperator zipFunction) { return zip(iterate(a), iterate(b), zipFunction).onClose(newCloseHandler(a, b)); } /** * Zips three IntStreams into a single IntStream until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction. * * @param a the first IntStream * @param b the second IntStream * @param c the third IntStream * @param zipFunction the function to combine elements from all three streams * @return a IntStream containing the results of applying the zip function to the elements of the input streams * @see Stream#zip(Stream, Stream, Stream, TriFunction) */ public static IntStream zip(final IntStream a, final IntStream b, final IntStream c, final IntTernaryOperator zipFunction) { return zip(iterate(a), iterate(b), iterate(c), zipFunction).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zips multiple IntStreams into a single IntStream until one of them runs out of values. * Each list of values is combined into a single value using the supplied zipFunction. * * @param streams the collection of IntStream to zip * @param zipFunction the function to combine elements from all the streams * @return a IntStream containing the results of applying the zip function to the elements of the input streams * @see Stream#zip(Collection, Function) */ public static IntStream zip(final Collection streams, final IntNFunction zipFunction) { //noinspection resource return Stream.zip(streams, zipFunction).mapToInt(ToIntFunction.UNBOX); } /** * Zips two int arrays into a single IntStream until all of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction. * If one array runs out of values before the other, the specified valueForNoneA or valueForNoneB is used. * * @param a the first int array * @param b the second int array * @param valueForNoneA the default value to use if the first array is shorter * @param valueForNoneB the default value to use if the second array is shorter * @param zipFunction the function to combine elements from both arrays * @return a IntStream containing the results of applying the zip function to the elements of the input arrays * @see Stream#zip(Object[], Object[], Object, Object, BiFunction) */ public static IntStream zip(final int[] a, final int[] b, final int valueForNoneA, final int valueForNoneB, final IntBinaryOperator zipFunction) { if (N.isEmpty(a) && N.isEmpty(b)) { return empty(); } return new IteratorIntStream(new IntIteratorEx() { private final int aLen = N.len(a), bLen = N.len(b), len = N.max(aLen, bLen); private int cursor = 0; private int ret = 0; @Override public boolean hasNext() { return cursor < len; } @Override public int nextInt() { if (cursor >= len) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } ret = zipFunction.applyAsInt(cursor < aLen ? a[cursor] : valueForNoneA, cursor < bLen ? b[cursor] : valueForNoneB); cursor++; return ret; } }); } /** * Zips three int arrays into a single IntStream until all of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction. * If one array runs out of values before the other, the specified valueForNoneA, valueForNoneB or valueForNoneC is used. * * @param a the first int array * @param b the second int array * @param c the third int array * @param valueForNoneA the default value to use if the first array is shorter * @param valueForNoneB the default value to use if the second array is shorter * @param valueForNoneC the default value to use if the third array is shorter * @param zipFunction the function to combine elements from all three arrays * @return a IntStream containing the results of applying the zip function to the elements of the input arrays * @see Stream#zip(Object[], Object[], Object[], Object, Object, Object, TriFunction) */ public static IntStream zip(final int[] a, final int[] b, final int[] c, final int valueForNoneA, final int valueForNoneB, final int valueForNoneC, final IntTernaryOperator zipFunction) { if (N.isEmpty(a) && N.isEmpty(b) && N.isEmpty(c)) { return empty(); } return new IteratorIntStream(new IntIteratorEx() { 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 int ret = 0; @Override public boolean hasNext() { return cursor < len; } @Override public int nextInt() { if (cursor >= len) { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } ret = zipFunction.applyAsInt(cursor < aLen ? a[cursor] : valueForNoneA, cursor < bLen ? b[cursor] : valueForNoneB, cursor < cLen ? c[cursor] : valueForNoneC); cursor++; return ret; } }); } /** * Zips two IntIterators into a single IntStream until all of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction. * If one iterator runs out of values before the other, the specified valueForNoneA or valueForNoneB is used. * * @param a the first IntIterator * @param b the second IntIterator * @param valueForNoneA the default value to use if the first iterator is shorter * @param valueForNoneB the default value to use if the second iterator is shorter * @param zipFunction the function to combine elements from both iterators * @return a IntStream containing the results of applying the zip function to the elements of the input iterators * @see Stream#zip(Iterator, Iterator, Object, Object, BiFunction) */ public static IntStream zip(final IntIterator a, final IntIterator b, final int valueForNoneA, final int valueForNoneB, final IntBinaryOperator zipFunction) { return new IteratorIntStream(new IntIteratorEx() { private final IntIterator iterA = a == null ? IntIterator.empty() : a; private final IntIterator iterB = b == null ? IntIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext(); } @Override public int nextInt() { if (iterA.hasNext()) { return zipFunction.applyAsInt(iterA.nextInt(), iterB.hasNext() ? iterB.nextInt() : valueForNoneB); } else { return zipFunction.applyAsInt(valueForNoneA, iterB.nextInt()); } } }); } /** * Zips three IntIterators into a single IntStream until all of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction. * If one iterator runs out of values before the other, the specified valueForNoneA, valueForNoneB or valueForNoneC is used. * * @param a the first IntIterator * @param b the second IntIterator * @param c the third IntIterator * @param valueForNoneA the default value to use if the first iterator is shorter * @param valueForNoneB the default value to use if the second iterator is shorter * @param valueForNoneC the default value to use if the third iterator is shorter * @param zipFunction the function to combine elements from all three iterators * @return a IntStream containing the results of applying the zip function to the elements of the input iterators * @see Stream#zip(Iterator, Iterator, Iterator, Object, Object, Object, TriFunction) */ public static IntStream zip(final IntIterator a, final IntIterator b, final IntIterator c, final int valueForNoneA, final int valueForNoneB, final int valueForNoneC, final IntTernaryOperator zipFunction) { return new IteratorIntStream(new IntIteratorEx() { private final IntIterator iterA = a == null ? IntIterator.empty() : a; private final IntIterator iterB = b == null ? IntIterator.empty() : b; private final IntIterator iterC = c == null ? IntIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public int nextInt() { if (iterA.hasNext()) { return zipFunction.applyAsInt(iterA.nextInt(), iterB.hasNext() ? iterB.nextInt() : valueForNoneB, iterC.hasNext() ? iterC.nextInt() : valueForNoneC); } else if (iterB.hasNext()) { return zipFunction.applyAsInt(valueForNoneA, iterB.nextInt(), iterC.hasNext() ? iterC.nextInt() : valueForNoneC); } else { return zipFunction.applyAsInt(valueForNoneA, valueForNoneB, iterC.nextInt()); } } }); } /** * Zips two IntStreams into a single IntStream until all of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction. * If one stream runs out of values before the other, the specified valueForNoneA or valueForNoneB is used. * * @param a the first IntStream * @param b the second IntStream * @param valueForNoneA the default value to use if the first stream is shorter * @param valueForNoneB the default value to use if the second stream is shorter * @param zipFunction the function to combine elements from both streams * @return a IntStream containing the results of applying the zip function to the elements of the input streams * @see Stream#zip(Stream, Stream, Object, Object, BiFunction) */ public static IntStream zip(final IntStream a, final IntStream b, final int valueForNoneA, final int valueForNoneB, final IntBinaryOperator zipFunction) { return zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction).onClose(newCloseHandler(a, b)); } /** * Zips three IntStreams into a single IntStream until all of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction. * If one stream runs out of values before the other, the specified valueForNoneA, valueForNoneB or valueForNoneC is used. * * @param a the first IntStream * @param b the second IntStream * @param c the third IntStream * @param valueForNoneA the default value to use if the first stream is shorter * @param valueForNoneB the default value to use if the second stream is shorter * @param valueForNoneC the default value to use if the third stream is shorter * @param zipFunction the function to combine elements from all three streams * @return a IntStream containing the results of applying the zip function to the elements of the input streams * @see Stream#zip(Stream, Stream, Stream, Object, Object, Object, TriFunction) */ public static IntStream zip(final IntStream a, final IntStream b, final IntStream c, final int valueForNoneA, final int valueForNoneB, final int valueForNoneC, final IntTernaryOperator zipFunction) { return zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zips multiple IntStreams into a single IntStream until all of them runs out of values. * Each list of values is combined into a single value using the supplied zipFunction. * If one stream runs out of values before the other, the specified valuesForNone is used. * * @param streams the collection of IntStream instances to zip * @param valuesForNone the default value to use if the corresponding stream is shorter * @param zipFunction the function to combine elements from all the streams * @return a IntStream containing the results of applying the zip function to the elements of the input streams * @see Stream#zip(Collection, List, Function) */ public static IntStream zip(final Collection streams, final int[] valuesForNone, final IntNFunction zipFunction) { //noinspection resource return Stream.zip(streams, valuesForNone, zipFunction).mapToInt(ToIntFunction.UNBOX); } /** * Merges two int arrays into a single IntStream based on the provided nextSelector function. * The nextSelector function determines which element to take next from the two arrays. * * @param a the first int array * @param b the second int array * @param nextSelector a function to determine which element should be selected as the next element. * The first parameter is selected if {@code MergeResult.TAKE_FIRST} is returned, otherwise the second parameter is selected. * @return a IntStream containing the merged elements from the two input arrays * @see Stream#merge(Object[], Object[], BiFunction) */ public static IntStream merge(final int[] a, final int[] b, final IntBiFunction nextSelector) { if (N.isEmpty(a)) { return of(b); } else if (N.isEmpty(b)) { return of(a); } return new IteratorIntStream(new IntIteratorEx() { 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 int nextInt() { if (cursorA < lenA) { if ((cursorB >= lenB) || (nextSelector.apply(a[cursorA], b[cursorB]) == MergeResult.TAKE_FIRST)) { return a[cursorA++]; } else { return b[cursorB++]; } } else if (cursorB < lenB) { return b[cursorB++]; } else { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } } }); } /** * Merges three int arrays into a single IntStream based on the provided nextSelector function. * The nextSelector function determines which element to take next from the three arrays. * * @param a the first int array * @param b the second int array * @param c the third int array * @param nextSelector a function to determine which element should be selected as the next element. * The first parameter is selected if {@code MergeResult.TAKE_FIRST} is returned, otherwise the second parameter is selected. * @return a IntStream containing the merged elements from the three input arrays * @see Stream#merge(Object[], Object[], Object[], BiFunction) */ public static IntStream merge(final int[] a, final int[] b, final int[] c, final IntBiFunction nextSelector) { //noinspection resource return merge(merge(a, b, nextSelector).iteratorEx(), IntStream.of(c).iteratorEx(), nextSelector); } /** * Merges two IntIterators into a single IntStream based on the provided nextSelector function. * The nextSelector function determines which element to take next from the two iterators. * * @param a the first IntIterator * @param b the second IntIterator * @param nextSelector a function to determine which element should be selected as the next element. * The first parameter is selected if {@code MergeResult.TAKE_FIRST} is returned, otherwise the second parameter is selected. * @return a IntStream containing the merged elements from the two input iterators * @see Stream#merge(Iterator, Iterator, BiFunction) */ public static IntStream merge(final IntIterator a, final IntIterator b, final IntBiFunction nextSelector) { return new IteratorIntStream(new IntIteratorEx() { private final IntIterator iterA = a == null ? IntIterator.empty() : a; private final IntIterator iterB = b == null ? IntIterator.empty() : b; private int nextA = 0; private int nextB = 0; private boolean hasNextA = false; private boolean hasNextB = false; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || hasNextA || hasNextB; } @Override public int nextInt() { if (hasNextA) { if (iterB.hasNext()) { if (nextSelector.apply(nextA, (nextB = iterB.nextInt())) == 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.nextInt()), 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.nextInt()), (nextB = iterB.nextInt())) == MergeResult.TAKE_FIRST) { hasNextB = true; return nextA; } else { hasNextA = true; return nextB; } } else { return iterA.nextInt(); } } else if (iterB.hasNext()) { return iterB.nextInt(); } else { throw new NoSuchElementException(ERROR_MSG_FOR_NO_SUCH_EX); } } }); } /** * Merges three IntIterators into a single IntStream based on the provided nextSelector function. * The nextSelector function determines which element to take next from the three iterators. * * @param a the first IntIterator * @param b the second IntIterator * @param c the third IntIterator * @param nextSelector a function to determine which element should be selected as the next element. * The first parameter is selected if {@code MergeResult.TAKE_FIRST} is returned, otherwise the second parameter is selected. * @return a IntStream containing the merged elements from the three input iterators * @see Stream#merge(Iterator, Iterator, Iterator, BiFunction) */ public static IntStream merge(final IntIterator a, final IntIterator b, final IntIterator c, final IntBiFunction nextSelector) { //noinspection resource return merge(merge(a, b, nextSelector).iteratorEx(), c, nextSelector); } /** * Merges two IntStreams into a single IntStream based on the provided nextSelector function. * The nextSelector function determines which element to take next from the two streams. * * @param a the first IntStream * @param b the second IntStream * @param nextSelector a function to determine which element should be selected as the next element. * The first parameter is selected if {@code MergeResult.TAKE_FIRST} is returned, otherwise the second parameter is selected. * @return a IntStream containing the merged elements from the two input streams * @see Stream#merge(Stream, Stream, BiFunction) */ public static IntStream merge(final IntStream a, final IntStream b, final IntBiFunction nextSelector) { return merge(iterate(a), iterate(b), nextSelector).onClose(newCloseHandler(a, b)); } /** * Merges three IntStreams into a single IntStream based on the provided nextSelector function. * The nextSelector function determines which element to take next from the three streams. * * @param a the first IntStream * @param b the second IntStream * @param c the third IntStream * @param nextSelector a function to determine which element should be selected as the next element. * The first parameter is selected if {@code MergeResult.TAKE_FIRST} is returned, otherwise the second parameter is selected. * @return a IntStream containing the merged elements from the three input streams * @see Stream#merge(Stream, Stream, Stream, BiFunction) */ public static IntStream merge(final IntStream a, final IntStream b, final IntStream c, final IntBiFunction nextSelector) { return merge(merge(a, b, nextSelector), c, nextSelector); } /** * Merges a collection of IntStream into a single IntStream based on the provided nextSelector function. * The nextSelector function determines which element to take next from the multiple streams. * * @param streams the collection of IntStream instances to merge * @param nextSelector a function to determine which element should be selected as the next element. * The first parameter is selected if {@code MergeResult.TAKE_FIRST} is returned, otherwise the second parameter is selected. * @return a IntStream containing the merged elements from the input IntStreams * @see Stream#merge(Collection, BiFunction) */ public static IntStream merge(final Collection streams, final IntBiFunction nextSelector) { if (N.isEmpty(streams)) { return empty(); } else if (streams.size() == 1) { return streams.iterator().next(); } else if (streams.size() == 2) { final Iterator iter = streams.iterator(); return merge(iter.next(), iter.next(), nextSelector); } final Iterator iter = streams.iterator(); IntStream result = merge(iter.next(), iter.next(), nextSelector); while (iter.hasNext()) { result = merge(result, iter.next(), nextSelector); } return result; } // /** // * Merges a collection of IntStream into a single IntStream in parallel. // * All the elements from each input IntStream will be merged into two queues by multiple threads first. // * Then these two new queues will be merged into one IntStream in current thread. // * This method is not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the two new queues. // * Consider using {@code merge}, which is totally lazy evaluation. // * // * @param streams the collection of IntStream to be merged // * @param nextSelector a function to determine which element should be selected as next element. // * @return a IntStream containing the merged elements from the input IntStreams // * @see Stream#parallelMerge(Collection, BiFunction) // */ // public static IntStream parallelMerge(final Collection streams, final IntBiFunction nextSelector) { // return parallelMerge(streams, nextSelector, DEFAULT_MAX_THREAD_NUM); // } // // /** // * Merges a collection of IntStream into a single IntStream in parallel. // * All the elements from each input IntStream will be merged into two queues by multiple threads first. // * Then these two new queues will be merged into one IntStream in current thread. // * This method is not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the two new queues. // * Consider using {@code merge}, which is totally lazy evaluation. // * // * @param streams the collection of IntStream to be merged // * @param nextSelector a function to determine which element should be selected as next element. // * @param maxThreadNum the max thread number for the parallel merge. // * @return a IntStream containing the merged elements from the input IntStreams // * @see Stream#parallelMerge(Collection, BiFunction, int) // */ // public static IntStream parallelMerge(final Collection streams, final IntBiFunction nextSelector, final int maxThreadNum) // throws IllegalArgumentException { // N.checkArgument(maxThreadNum > 0, "'maxThreadNum' must not less than 1"); // // if (maxThreadNum <= 1) { // return merge(streams, nextSelector); // } else if (N.isEmpty(streams)) { // return empty(); // } else if (streams.size() == 1) { // return streams.iterator().next(); // } else if (streams.size() == 2) { // final Iterator iter = streams.iterator(); // return merge(iter.next(), iter.next(), nextSelector); // } else if (streams.size() == 3) { // final Iterator iter = streams.iterator(); // return merge(iter.next(), iter.next(), iter.next(), nextSelector); // } // // final Supplier supplier = () -> { // final Queue queue = N.newLinkedList(); // // queue.addAll(streams); // // final Holder eHolder = new Holder<>(); // final MutableInt cnt = MutableInt.of(streams.size()); // final List> futureList = new ArrayList<>(streams.size() - 1); // // final int threadNum = N.min(maxThreadNum, streams.size() / 2 + 1); // // AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(DEFAULT_ASYNC_EXECUTOR, threadNum, 0); // // for (int i = 0; i < threadNum; i++) { // asyncExecutorToUse = execute(asyncExecutorToUse, threadNum, 0, i, futureList, () -> { // IntStream a = null; // IntStream b = null; // IntStream c1 = null; // // try { // while (eHolder.value() == null) { // synchronized (queue) { // if (cnt.value() > 2 && queue.size() > 1) { // a = queue.poll(); // b = queue.poll(); // // cnt.decrement(); // } else { // break; // } // } // // c1 = IntStream.of(merge(a, b, nextSelector).toArray()); // // synchronized (queue) { // queue.offer(c1); // } // } // } catch (final Throwable e) { // NOSONAR // setError(eHolder, e); // } // }); // } // // completeAndShutdownTempExecutor(futureList, eHolder, streams, asyncExecutorToUse); // // return merge(queue.poll(), queue.poll(), nextSelector); // }; // // return Stream.just(supplier).flatMapToInt(Supplier::get); // } public abstract static class IntStreamEx extends IntStream { private IntStreamEx(final boolean sorted, final Collection closeHandlers) { //NOSONAR super(sorted, closeHandlers); // Factory class. } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy