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 extends T> mapper);
/**
*
* @param mapper
* @return
*/
@ParallelSupported
@IntermediateOp
public abstract IntStream flatMap(IntFunction extends IntStream> 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 extends Collection extends T>> mapper)} instead
* @see #flatmapToObj(IntFunction)
*/
@Deprecated
@ParallelSupported
@IntermediateOp
IntStream flattMap(@SuppressWarnings("unused") final IntFunction extends Collection> mapper) throws UnsupportedOperationException { // NOSONAR
throw new UnsupportedOperationException();
}
/**
*
* @param mapper
* @return
*/
@Beta
@ParallelSupported
@IntermediateOp
public abstract IntStream flattmap(IntFunction extends java.util.stream.IntStream> mapper); //NOSONAR
/**
*
* @param mapper
* @return
*/
@ParallelSupported
@IntermediateOp
public abstract CharStream flatMapToChar(IntFunction extends CharStream> mapper);
/**
*
* @param mapper
* @return
*/
@ParallelSupported
@IntermediateOp
public abstract ByteStream flatMapToByte(IntFunction extends ByteStream> mapper);
/**
*
* @param mapper
* @return
*/
@ParallelSupported
@IntermediateOp
public abstract ShortStream flatMapToShort(IntFunction extends ShortStream> mapper);
/**
*
* @param mapper
* @return
*/
@ParallelSupported
@IntermediateOp
public abstract LongStream flatMapToLong(IntFunction extends LongStream> mapper);
/**
*
* @param mapper
* @return
*/
@ParallelSupported
@IntermediateOp
public abstract FloatStream flatMapToFloat(IntFunction extends FloatStream> mapper);
/**
*
* @param mapper
* @return
*/
@ParallelSupported
@IntermediateOp
public abstract DoubleStream flatMapToDouble(IntFunction extends DoubleStream> mapper);
/**
*
* @param
* @param mapper
* @return
*/
@ParallelSupported
@IntermediateOp
public abstract Stream flatMapToObj(IntFunction extends Stream extends T>> mapper);
/**
*
* @param
* @param mapper
* @return
*/
@ParallelSupported
@IntermediateOp
public abstract Stream flatmapToObj(IntFunction extends Collection extends T>> 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 extends T> 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 super Integer> 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 extends K, E> keyMapper,
Throwables.IntFunction extends V, E2> 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 extends K, E> keyMapper,
Throwables.IntFunction extends V, E2> valueMapper, Supplier extends M> 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 extends K, E> keyMapper,
Throwables.IntFunction extends V, E2> 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 extends K, E> keyMapper,
Throwables.IntFunction extends V, E2> valueMapper, BinaryOperator mergeFunction, Supplier extends M> 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 extends K, E> keyMapper,
final Collector super Integer, ?, D> 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 extends K, E> keyMapper,
final Collector super Integer, ?, D> downstream, final Supplier extends M> 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 super R> 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 super R> 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 super java.util.stream.IntStream, ? extends java.util.stream.IntStream> 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 super java.util.stream.IntStream, ? extends java.util.stream.IntStream> transfer) {
return transformB(transfer, false);
}
/**
*
* @param transfer
* @param deferred
* @return
* @throws IllegalArgumentException
*/
@Beta
@SequentialOnly
@IntermediateOp
public IntStream transformB(final Function super java.util.stream.IntStream, ? extends java.util.stream.IntStream> 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 super AC, Integer> 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 super AC, Integer> 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 super AC, Integer> 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 super AC, Integer> 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 extends IntStream> streams) {
return N.isEmpty(streams) ? empty() : new IteratorIntStream(new IntIteratorEx() { //NOSONAR
private final Iterator extends IntStream> 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 extends IntIterator> intIterators) {
if (N.isEmpty(intIterators)) {
return empty();
}
return new IteratorIntStream(new IntIteratorEx() {
private final Iterator extends IntIterator> 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 extends IntStream> 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 extends IntStream> 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 extends IntStream> 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 extends IntStream> iter = streams.iterator();
return merge(iter.next(), iter.next(), nextSelector);
}
final Iterator extends IntStream> 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 extends IntStream> 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 extends IntStream> 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 extends IntStream> iter = streams.iterator();
// return merge(iter.next(), iter.next(), nextSelector);
// } else if (streams.size() == 3) {
// final Iterator extends IntStream> 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