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

org.d2ab.sequence.Sequence Maven / Gradle / Ivy

/*
 * Copyright 2016 Daniel Skogquist Åborg
 *
 * 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 org.d2ab.sequence;

import org.d2ab.collection.*;
import org.d2ab.function.ObjIntFunction;
import org.d2ab.function.ObjIntPredicate;
import org.d2ab.function.ToCharFunction;
import org.d2ab.iterator.*;
import org.d2ab.iterator.chars.CharIterator;
import org.d2ab.iterator.doubles.DoubleIterator;
import org.d2ab.iterator.ints.IntIterator;
import org.d2ab.iterator.longs.LongIterator;
import org.d2ab.util.Pair;

import java.util.*;
import java.util.Map.Entry;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.function.BinaryOperator.maxBy;
import static java.util.function.BinaryOperator.minBy;

/**
 * An {@link Iterable} sequence of elements with {@link Stream}-like operations for refining, transforming and collating
 * the list of elements.
 */
@FunctionalInterface
public interface Sequence extends IterableCollection {
	/**
	 * Create an empty {@code Sequence} with no items.
	 *
	 * @see #of(Object)
	 * @see #of(Object...)
	 * @see #from(Iterable)
	 */
	static  Sequence empty() {
		return ListSequence.empty();
	}

	/**
	 * Create a {@code Sequence} with one item.
	 *
	 * @see #of(Object...)
	 * @see #from(Iterable)
	 */
	static  Sequence of(T item) {
		return ListSequence.of(item);
	}

	/**
	 * Create a {@code Sequence} with the given items.
	 *
	 * @see #of(Object)
	 * @see #from(Iterable)
	 */
	@SafeVarargs
	static  Sequence of(T... items) {
		return ListSequence.of(items);
	}

	/**
	 * Create a {@code Sequence} from an {@link Iterable} of items.
	 *
	 * @see #of(Object)
	 * @see #of(Object...)
	 * @see #once(Iterator)
	 */
	static  Sequence from(Iterable iterable) {
		if (iterable instanceof List)
			return ListSequence.from((List) iterable);

		if (iterable instanceof Collection)
			return CollectionSequence.from((Collection) iterable);

		return iterable::iterator;
	}

	/**
	 * Create a {@code Sequence} of {@link Entry} key/value items from a {@link Map} of items. The resulting
	 * {@code Sequence} can be mapped using {@link Pair} items, which implement {@link Entry} and can thus be
	 * processed as part of the {@code Sequence}'s transformation steps.
	 *
	 * @see #of
	 * @see #from(Iterable)
	 */
	static  Sequence> from(Map map) {
		return from(map.entrySet());
	}

	/**
	 * Create a concatenated {@code Sequence} from several {@link Iterable}s which are concatenated together to form
	 * the stream of items in the {@code Sequence}.
	 *
	 * @see #concat(Iterable)
	 * @see #of(Object)
	 * @see #of(Object...)
	 * @see #from(Iterable)
	 * @since 1.1.1
	 */
	@SafeVarargs
	static  Sequence concat(Iterable... iterables) {
		Sequence> iterablesSequence = Sequence.of(iterables);
		if (iterablesSequence.all(List.class))
			return ListSequence.concat(iterablesSequence.map(iterable -> (List) iterable).asList());

		if (iterablesSequence.all(Collection.class))
			return CollectionSequence.concat(iterablesSequence.map(iterable -> (Collection) iterable).asList());

		return ChainingIterable.concat(iterables)::iterator;
	}

	/**
	 * Create a concatenated {@code Sequence} from several {@link Iterable}s which are concatenated together to form
	 * the stream of items in the {@code Sequence}.
	 *
	 * @see #concat(Iterable[])
	 * @see #of(Object)
	 * @see #of(Object...)
	 * @see #from(Iterable)
	 * @since 1.1.1
	 */
	static  Sequence concat(Iterable> iterables) {
		Sequence> iterablesSequence = Sequence.from(iterables);
		if (iterablesSequence.all(List.class))
			return ListSequence.concat(iterablesSequence.map(iterable -> (List) iterable).asList());

		if (iterablesSequence.all(Collection.class))
			return CollectionSequence.concat(iterablesSequence.map(iterable -> (Collection) iterable));

		return new ChainingIterable<>(iterables)::iterator;
	}

	/**
	 * Create a one-pass-only {@code Sequence} from an {@link Iterator} of items. Note that {@code Sequences} created
	 * from {@link Iterator}s will be exhausted when the given iterator has been passed over. Further attempts will
	 * register the {@code Sequence} as empty. If the sequence is terminated partway through iteration, further
	 * calls to {@link #iterator()} will pick up where the previous iterator left off. If {@link #iterator()} calls
	 * are interleaved, calls to the given iterator will be interleaved.
	 *
	 * @see #of(Object)
	 * @see #of(Object...)
	 * @see #from(Iterable)
	 * @see #cache(Iterator)
	 * @since 1.1
	 */
	static  Sequence once(Iterator iterator) {
		return from(Iterables.once(iterator));
	}

	/**
	 * Create a one-pass-only {@code Sequence} from a {@link Stream} of items. Note that {@code Sequences} created
	 * from {@link Stream}s will be exhausted when the given stream has been passed over. Further attempts will
	 * register the {@code Sequence} as empty. If the sequence is terminated partway through iteration, further
	 * calls to {@link #iterator()} will pick up where the previous iterator left off. If {@link #iterator()} calls
	 * are interleaved, calls to the given stream will be interleaved.
	 *
	 * @see #of(Object)
	 * @see #of(Object...)
	 * @see #from(Iterable)
	 * @see #once(Iterator)
	 * @see #cache(Stream)
	 * @since 1.1
	 */
	static  Sequence once(Stream stream) {
		return once(stream.iterator());
	}

	/**
	 * Create a {@code Sequence} with a cached copy of an {@link Iterable} of items.
	 *
	 * @see #cache(Iterator)
	 * @see #cache(Stream)
	 * @see #from(Iterable)
	 * @since 1.1
	 */
	static  Sequence cache(Iterable iterable) {
		return from(Iterables.toList(iterable));
	}

	/**
	 * Create a {@code Sequence} with a cached copy of an {@link Iterator} of items.
	 *
	 * @see #cache(Iterable)
	 * @see #cache(Stream)
	 * @see #once(Iterator)
	 * @since 1.1
	 */
	static  Sequence cache(Iterator iterator) {
		return from(Iterators.toList(iterator));
	}

	/**
	 * Create a {@code Sequence} with a cached copy of a {@link Stream} of items.
	 *
	 * @see #cache(Iterable)
	 * @see #cache(Iterator)
	 * @see #once(Stream)
	 * @since 1.1
	 */
	static  Sequence cache(Stream stream) {
		return from(stream.collect(Collectors.toList()));
	}

	/**
	 * @return a new empty mutable {@code Sequence}.
	 */
	static  Sequence create() {
		return ListSequence.create();
	}

	/**
	 * @return a new empty mutable {@code Sequence} with the given initial capacity.
	 */
	static  Sequence withCapacity(int capacity) {
		return ListSequence.withCapacity(capacity);
	}

	/**
	 * @return a new mutable {@code Sequence} initialized with the given elements.
	 */
	@SafeVarargs
	static  Sequence createOf(T... ts) {
		return ListSequence.createOf(ts);
	}

	/**
	 * @return a new mutable {@code Sequence} initialized with the elements in the given {@link Collection}.
	 */
	static  Sequence createFrom(Collection c) {
		return ListSequence.createFrom(c);
	}

	/**
	 * @return a new mutable {@code Sequence} initialized with the elements in the given {@link Iterable}.
	 */
	@SuppressWarnings("unchecked")
	static  Sequence createFrom(Iterable iterable) {
		if (iterable instanceof Collection)
			return createFrom((Collection) iterable);

		return ListSequence.createFrom(iterable);
	}

	/**
	 * @return a new mutable {@code Sequence} initialized with the remaining elements in the given {@link Iterator}.
	 */
	static  Sequence createFrom(Iterator iterator) {
		return ListSequence.createFrom(iterator);
	}

	/**
	 * A {@code Sequence} of all the positive {@link Integer} numbers starting at {@code 1} and ending at {@link
	 * Integer#MAX_VALUE} inclusive.
	 *
	 * @see #intsFromZero()
	 * @see #intsFrom(int)
	 * @see #range(int, int)
	 */
	static Sequence ints() {
		return range(1, Integer.MAX_VALUE);
	}

	/**
	 * A {@code Sequence} of all the positive {@link Integer} numbers starting at {@code 0} and ending at {@link
	 * Integer#MAX_VALUE} inclusive.
	 *
	 * @see #ints()
	 * @see #intsFrom(int)
	 * @see #range(int, int)
	 */
	static Sequence intsFromZero() {
		return range(0, Integer.MAX_VALUE);
	}

	/**
	 * A {@code Sequence} of all the {@link Integer} numbers starting at the given start and ending at {@link
	 * Integer#MAX_VALUE} inclusive.
	 * 

* The start value may be negative, in which case the sequence will continue towards positive numbers and * eventually {@link Integer#MAX_VALUE}. * * @see #ints() * @see #range(int, int) * @since 1.1 */ static Sequence intsFrom(int start) { return range(start, Integer.MAX_VALUE); } /** * A {@code Sequence} of all the {@link Integer} numbers between the given start and end positions, inclusive. * If the end index is less than the start index, the resulting {@code Sequence} will be counting down from the * start to the end. * * @see #ints() * @see #intsFromZero() * @see #intsFrom(int) */ static Sequence range(int start, int end) { UnaryOperator next = (end > start) ? i -> ++i : i -> --i; return recurse(start, next).endingAt(end); } /** * A {@code Sequence} of all the positive {@link Long} numbers starting at {@code 1} and ending at {@link * Long#MAX_VALUE} inclusive. * * @see #longsFromZero() * @see #longsFrom(long) * @see #range(long, long) */ static Sequence longs() { return range(1, Long.MAX_VALUE); } /** * A {@code Sequence} of all the positive {@link Long} numbers starting at {@code 0} and ending at {@link * Long#MAX_VALUE} inclusive. * * @see #longs() * @see #longsFrom(long) * @see #range(long, long) */ static Sequence longsFromZero() { return range(0, Long.MAX_VALUE); } /** * A {@code Sequence} of all the {@link Long} numbers starting at the given value and ending at {@link * Long#MAX_VALUE} inclusive. *

* The start value may be negative, in which case the sequence will continue towards positive numbers and * eventually {@link Long#MAX_VALUE}. * * @see #longs() * @see #longsFromZero() * @see #range(long, long) * @since 1.1 */ static Sequence longsFrom(long start) { return range(start, Long.MAX_VALUE); } /** * A {@code Sequence} of all the {@link Long} numbers between the given start and end positions, inclusive. * If the end index is less than the start index, the resulting {@code Sequence} will be counting down from the * start to the end. * * @see #longs() * @see #longsFromZero() * @see #longsFrom(long) */ static Sequence range(long start, long end) { UnaryOperator next = (end > start) ? i -> ++i : i -> --i; return recurse(start, next).endingAt(end); } /** * A {@code Sequence} of all the {@link Character} values starting at {@link Character#MIN_VALUE} and ending at * {@link Character#MAX_VALUE} inclusive. * * @see #charsFrom(char) * @see #range(char, char) */ static Sequence chars() { return range(Character.MIN_VALUE, Character.MAX_VALUE); } /** * A {@code Sequence} of all the {@link Character} values starting at the given value and ending at {@link * Character#MAX_VALUE} inclusive. * * @see #chars() * @see #range(char, char) * @since 1.1 */ static Sequence charsFrom(char start) { return range(start, Character.MAX_VALUE); } /** * A {@code Sequence} of all the {@link Character} values between the given start and end positions, inclusive. * If the end index is less than the start index, the resulting {@code Sequence} will be counting down from the * start to the end. * * @see #chars() * @see #charsFrom(char) */ static Sequence range(char start, char end) { UnaryOperator next = (end > start) ? c -> (char) (c + 1) : c -> (char) (c - 1); return recurse(start, next).endingAt(end); } /** * @return an infinite {@code Sequence} generated by repeatedly calling the given supplier. The returned {@code * Sequence} never terminates naturally. If {@link #iterator()} is called multiple times, further iterators will * pick up where the previous iterator left off in the given supplier. If iterator calls are interleaved, calls to * the supplier will be interleaved. * * @see #multiGenerate(Supplier) * @see #recurse(Object, UnaryOperator) * @see #endingAt(Object) * @see #until(Object) */ static Sequence generate(Supplier supplier) { return () -> (InfiniteIterator) supplier::get; } /** * @return an infinite {@code Sequence} where each {@link #iterator()} is generated by polling for a supplier and * then using it to generate the sequence of elements. The sequence never terminates. * * @see #generate(Supplier) * @see #recurse(Object, UnaryOperator) * @see #endingAt(Object) * @see #until(Object) */ static Sequence multiGenerate(Supplier> supplierSupplier) { return () -> { Supplier supplier = supplierSupplier.get(); return (InfiniteIterator) supplier::get; }; } /** * Returns a {@code Sequence} produced by recursively applying the given operation to the given seed, which forms * the first element of the sequence, the second being {@code f(seed)}, the third [@code f(f(seed))} and so on. * The returned {@code Sequence} never terminates naturally. * * @return a {@code Sequence} produced by recursively applying the given operation to the given seed * * @see #recurse(Object, Function, Function) * @see #multiGenerate(Supplier) * @see #endingAt(Object) * @see #until(Object) */ static Sequence recurse(T seed, UnaryOperator f) { return () -> new RecursiveIterator<>(seed, f); } /** * Returns a {@code Sequence} produced by recursively applying the given mapper {@code f} and incrementer * {@code g} operations to the given seed, the first element being {@code f(seed)}, the second being * {@code f(g(f(seed)))}, the third {@code f(g(f(g(f(seed)))))} and so on. The returned {@code Sequence} never * terminates naturally. * * @param f a mapper function for producing elements that are to be included in the sequence, the first being * f(seed) * @param g an incrementer function for producing the next unmapped element to be included in the sequence, applied * to the first mapped element f(seed) to produce the second unmapped value * * @return a {@code Sequence} produced by recursively applying the given mapper and incrementer operations to the * given seed * * @see #recurse(Object, UnaryOperator) * @see #endingAt(Object) * @see #until(Object) */ static Sequence recurse(T seed, Function f, Function g) { return recurse(f.apply(seed), f.compose(g)::apply); } /** * @return an immutable view of this {@code Sequence}. */ default Sequence immutable() { return () -> new ImmutableIterator<>(iterator()); } /** * Terminate this {@code Sequence} just before the given element is encountered, not including the element in the * {@code Sequence}. * * @see #untilNull() * @see #until(Predicate) * @see #endingAt(Object) * @see #multiGenerate(Supplier) * @see #recurse(Object, UnaryOperator) * @see #recurse(Object, Function, Function) * @see #repeat() */ default Sequence until(T terminal) { return () -> new ExclusiveTerminalIterator<>(iterator(), terminal); } /** * Terminate this {@code Sequence} when the given element is encountered, including the element as the last element * in the {@code Sequence}. * * @see #endingAtNull * @see #endingAt(Predicate) * @see #until(Object) * @see #multiGenerate(Supplier) * @see #recurse(Object, UnaryOperator) * @see #recurse(Object, Function, Function) * @see #repeat() */ default Sequence endingAt(T terminal) { return () -> new InclusiveTerminalIterator<>(iterator(), terminal); } /** * Terminate this {@code Sequence} just before a null element is encountered, not including the null in the * {@code Sequence}. * * @see #until(Object) * @see #until(Predicate) * @see #endingAtNull * @see #multiGenerate(Supplier) * @see #recurse(Object, UnaryOperator) * @see #recurse(Object, Function, Function) * @see #repeat() */ default Sequence untilNull() { return () -> new ExclusiveTerminalIterator<>(iterator(), (T) null); } /** * Terminate this {@code Sequence} when a null element is encountered, including the null as the last element * in the {@code Sequence}. * * @see #endingAt(Object) * @see #endingAt(Predicate) * @see #untilNull * @see #multiGenerate(Supplier) * @see #recurse(Object, UnaryOperator) * @see #recurse(Object, Function, Function) * @see #repeat() */ default Sequence endingAtNull() { return () -> new InclusiveTerminalIterator<>(iterator(), (T) null); } /** * Terminate this {@code Sequence} just before the given predicate is satisfied, not including the element that * satisfies the predicate in the {@code Sequence}. * * @see #until(Object) * @see #untilNull() * @see #endingAt(Predicate) * @see #multiGenerate(Supplier) * @see #recurse(Object, UnaryOperator) * @see #recurse(Object, Function, Function) * @see #repeat() */ default Sequence until(Predicate terminal) { return () -> new ExclusiveTerminalIterator<>(iterator(), terminal); } /** * Terminate this {@code Sequence} when the given predicate is satisfied, including the element that satisfies * the predicate as the last element in the {@code Sequence}. * * @see #endingAt(Object) * @see #endingAtNull() * @see #until(Predicate) * @see #multiGenerate(Supplier) * @see #recurse(Object, UnaryOperator) * @see #recurse(Object, Function, Function) * @see #repeat() */ default Sequence endingAt(Predicate terminal) { return () -> new InclusiveTerminalIterator<>(iterator(), terminal); } /** * Begin this {@code Sequence} just after the given element is encountered, not including the element in the * {@code Sequence}. * * @see #startingAfter(Predicate) * @see #startingFrom(Object) * @since 1.1 */ default Sequence startingAfter(T element) { return () -> new ExclusiveStartingIterator<>(iterator(), element); } /** * Begin this {@code Sequence} when the given element is encountered, including the element as the first element * in the {@code Sequence}. * * @see #startingFrom(Predicate) * @see #startingAfter(Object) * @since 1.1 */ default Sequence startingFrom(T element) { return () -> new InclusiveStartingIterator<>(iterator(), element); } /** * Begin this {@code Sequence} just after the given predicate is satisfied, not including the element that * satisfies the predicate in the {@code Sequence}. * * @see #startingAfter(Object) * @see #startingFrom(Predicate) * @since 1.1 */ default Sequence startingAfter(Predicate predicate) { return () -> new ExclusiveStartingIterator<>(iterator(), predicate); } /** * Begin this {@code Sequence} when the given predicate is satisfied, including the element that satisfies * the predicate as the first element in the {@code Sequence}. * * @see #startingFrom(Object) * @see #startingAfter(Predicate) * @since 1.1 */ default Sequence startingFrom(Predicate predicate) { return () -> new InclusiveStartingIterator<>(iterator(), predicate); } /** * Map the values in this {@code Sequence} to another set of values specified by the given {@code mapper} function. * * @see #biMap(Function, Function) * @see #mapIndexed(ObjIntFunction) * @see #mapBack(BiFunction) * @see #mapForward(BiFunction) * @see #flatten() * @see #flatten(Function) * @see #toChars(ToCharFunction) * @see #toInts(ToIntFunction) * @see #toLongs(ToLongFunction) * @see #toDoubles(ToDoubleFunction) */ default Sequence map(Function mapper) { return () -> new MappingIterator<>(iterator(), mapper); } /** * Map the values in this {@code Sequence} to another set of values specified by the given {@code mapper} * functions, * allowing for backwards mapping using {@code backMapper} so elements can be added to underlying * {@link Collection}s after being mapped. * * @see #map(Function) */ default Sequence biMap(Function mapper, Function backMapper) { return () -> new MappingIterator<>(iterator(), mapper); } /** * Cast the values in this {@code Sequence} to the given {@link Class}. * * @see #map(Function) */ @SuppressWarnings({"unchecked", "unused"}) default Sequence cast(Class clazz) { return (Sequence) this; } /** * Map the values in this {@code Sequence} to another set of values specified by the given {@code mapper} function. * In addition to the current element, the mapper has access to the index of each element. * * @see #map(Function) * @see #mapBack(BiFunction) * @see #mapForward(BiFunction) * @see #flatten() * @see #flatten(Function) * @see #toChars(ToCharFunction) * @see #toInts(ToIntFunction) * @see #toLongs(ToLongFunction) * @see #toDoubles(ToDoubleFunction) * @since 1.2 */ default Sequence mapIndexed(ObjIntFunction mapper) { return () -> new IndexingMappingIterator<>(iterator(), mapper); } /** * Map this {@code Sequence} to another sequence while peeking at the previous element in the iteration. *

* The mapper has access to the previous element and the next element in the iteration. {@code null} is provided * as the first previous value when the next element is the first value in the sequence. * * @see #mapBack(Object, BiFunction) */ default Sequence mapBack(BiFunction mapper) { return mapBack(null, mapper); } /** * Map this {@code Sequence} to another sequence while peeking at the following element in the iteration. *

* The mapper has access to the next element and the following element in the iteration. {@code null} is * provided as the last following value when the next element is the last value in the sequence. * * @see #mapForward(Object, BiFunction) */ default Sequence mapForward(BiFunction mapper) { return mapForward(null, mapper); } /** * Map this {@code Sequence} to another sequence while peeking at the previous element in the iteration. *

* The mapper has access to the previous element and the next element in the iteration. The given replacement value * is provided as a prefix to the sequence for the first value in the sequence. * * @see #mapBack(BiFunction) */ default Sequence mapBack(T replacement, BiFunction mapper) { return () -> new BackPeekingMappingIterator(iterator(), replacement) { @Override protected U map(T previous, T next) { return mapper.apply(previous, next); } }; } /** * Map this {@code Sequence} to another sequence while peeking at the following element in the iteration. *

* The mapper has access to the next element and the following element in the iteration. The given replacement * value is provided as a suffix to the sequence for the last value in the sequence. * * @see #mapForward(BiFunction) */ default Sequence mapForward(T replacement, BiFunction mapper) { return () -> new ForwardPeekingMappingIterator(iterator(), replacement) { @Override protected T mapFollowing(boolean hasFollowing, T following) { return following; } @Override protected U mapNext(T next, T following) { return mapper.apply(next, following); } }; } /** * Skip a set number of steps in this {@code Sequence}. */ default Sequence skip(int skip) { return () -> new SkippingIterator<>(iterator(), skip); } /** * Skip a set number of steps at the end of this {@code Sequence}. * * @since 1.1 */ default Sequence skipTail(int skip) { if (skip == 0) return this; return () -> new TailSkippingIterator<>(iterator(), skip); } /** * Limit the maximum number of results returned by this {@code Sequence}. */ default Sequence limit(int limit) { return () -> new LimitingIterator<>(iterator(), limit); } /** * Append the given elements to the end of this {@code Sequence}. */ @SuppressWarnings("unchecked") default Sequence append(T... items) { return append(Iterables.of(items)); } /** * Append the elements of the given {@link Iterable} to the end of this {@code Sequence}. * * @see #cache(Iterable) */ default Sequence append(Iterable iterable) { return ChainingIterable.concat(this, iterable)::iterator; } /** * Append the elements of the given {@link Iterator} to the end of this {@code Sequence}. *

* The appended elements will only be available on the first traversal of the resulting {@code Sequence}. * * @see #cache(Iterator) */ default Sequence append(Iterator iterator) { return append(Iterables.once(iterator)); } /** * Append the elements of the given {@link Stream} to the end of this {@code Sequence}. *

* The appended elements will only be available on the first traversal of the resulting {@code Sequence}. * * @see #cache(Stream) */ default Sequence append(Stream stream) { return append(stream.iterator()); } /** * Filter the elements in this {@code Sequence}, keeping only the elements that match the given {@link Predicate}. */ default Sequence filter(Predicate predicate) { return () -> new FilteringIterator<>(iterator(), predicate); } /** * Filter the elements in this {@code Sequence}, keeping only the elements that match the given * {@link ObjIntPredicate}, which is passed the current element and its index in the sequence. * * @since 1.2 */ default Sequence filterIndexed(ObjIntPredicate predicate) { return () -> new IndexedFilteringIterator<>(iterator(), predicate); } /** * Filter the elements in this {@code Sequence}, keeping only the elements are instances of the given * {@link Class}. * * @since 1.2 */ @SuppressWarnings("unchecked") default Sequence filter(Class target) { return (Sequence) filter(target::isInstance); } /** * Filter the elements in this {@code Sequence} while peeking at the previous element in the iteration, keeping * only the elements that match the given {@link BiPredicate}. *

* The predicate has access to the previous element and the next element in the iteration. {@code null} is provided * as a prefix to the sequence for first value in the sequence. * * @see #filterBack(Object, BiPredicate) */ default Sequence filterBack(BiPredicate predicate) { return filterBack(null, predicate); } /** * Filter the elements in this {@code Sequence} while peeking at the previous element in the iteration, keeping * only the elements that match the given {@link BiPredicate}. *

* The predicate has access to the previous element and the next element in the iteration. The given replacement * value is provided as a prefix to the sequence for the first value in the sequence. * * @see #filterBack(BiPredicate) */ default Sequence filterBack(T replacement, BiPredicate predicate) { return () -> new BackPeekingFilteringIterator<>(iterator(), replacement, predicate); } /** * Filter the elements in this {@code Sequence} while peeking at the next element in the iteration, keeping * only the elements that match the given {@link BiPredicate}. *

* The predicate has access to the current element and the next element in the iteration. {@code null} is provided * as a suffix to the sequence for the last value in the sequence. * * @see #filterForward(Object, BiPredicate) */ default Sequence filterForward(BiPredicate predicate) { return filterForward(null, predicate); } /** * Filter the elements in this {@code Sequence} while peeking at the next element in the iteration, keeping * only the elements that match the given {@link BiPredicate}. *

* The predicate has access to the current element and the next element in the iteration. The given replacement * value is provided as a suffix to the sequence for the last value in the sequence. * * @see #filterForward(BiPredicate) */ default Sequence filterForward(T replacement, BiPredicate predicate) { return () -> new ForwardPeekingFilteringIterator<>(iterator(), replacement, predicate); } /** * @return a {@code Sequence} containing only the elements found in the given target array. * * @since 1.2 */ @SuppressWarnings("unchecked") default Sequence including(T... elements) { return filter(e -> Arrayz.contains(elements, e)); } /** * @return a {@code Sequence} containing only the elements found in the given target iterable. * * @since 1.2 */ default Sequence including(Iterable elements) { return filter(e -> Iterables.contains(elements, e)); } /** * @return a {@code Sequence} containing only the elements not found in the given target array. * * @since 1.2 */ @SuppressWarnings("unchecked") default Sequence excluding(T... elements) { return filter(e -> !Arrayz.contains(elements, e)); } /** * @return a {@code Sequence} containing only the elements not found in the given target iterable. * * @since 1.2 */ default Sequence excluding(Iterable elements) { return filter(e -> !Iterables.contains(elements, e)); } /** * Flatten the elements in this {@code Sequence} according to the given mapper {@link Function}. The resulting * {@code Sequence} contains the elements that is the result of applying the mapper {@link Function} to each * element, appended together inline as a single {@code Sequence}. * * @see #flatten() * @see #map(Function) * @see #toChars(ToCharFunction) * @see #toInts(ToIntFunction) * @see #toLongs(ToLongFunction) * @see #toDoubles(ToDoubleFunction) */ // TODO: Add flattenIterator, flattenArray, etc default Sequence flatten(Function> mapper) { return ChainingIterable.flatten(this, mapper)::iterator; } /** * Flatten the elements in this {@code Sequence}. The resulting {@code Sequence} contains the elements that is the * result of flattening each element, inline. Allowed elements that can be flattened are {@link Iterator}, * {@link Iterable}, {@code object array}, {@link Pair}, {@link Entry} and {@link Stream}. Elements of another type * will result in a {@link ClassCastException}. * * @throws ClassCastException if a non-collection element is encountered in the {@code Sequence}. * @see #flatten(Function) * @see #map(Function) * @see #toChars(ToCharFunction) * @see #toInts(ToIntFunction) * @see #toLongs(ToLongFunction) * @see #toDoubles(ToDoubleFunction) */ default Sequence flatten() { return ChainingIterable.concatAny(this)::iterator; } /** * Collect the elements in this {@code Sequence} into an array of the type determined by the given array * constructor. */ default A[] toArray(IntFunction constructor) { List list = toList(); return list.toArray(constructor.apply(list.size())); } /** * Collect the elements in this {@code Sequence} into a {@link List}. */ default List toList() { return toList(ArrayList::new); } /** * Collect the elements in this {@code Sequence} into a {@link List} of the type determined by the given * constructor. */ default List toList(Supplier> constructor) { return toCollection(constructor); } /** * Collect the elements in this {@code Sequence} into a {@link Set}. */ default Set toSet() { return toSet(HashSet::new); } /** * Collect the elements in this {@code Sequence} into a {@link Set} of the type determined by the given * constructor. */ default > S toSet(Supplier constructor) { return toCollection(constructor); } /** * Collect the elements in this {@code Sequence} into a {@link SortedSet}. */ default SortedSet toSortedSet() { return toSet(TreeSet::new); } /** * Convert this {@code Sequence} of {@link Map.Entry} values into a {@link Map}. * * @throws ClassCastException if this {@code Sequence} is not of {@link Map.Entry}. */ default Map toMap() { return toMap(HashMap::new); } /** * Convert this {@code Sequence} of {@link Map.Entry} values into a {@link Map} of the type determined by the given * constructor. * * @throws ClassCastException if this {@code Sequence} is not of {@link Map.Entry}. */ @SuppressWarnings("unchecked") default , K, V> M toMap(Supplier constructor) { Sequence> entrySequence = (Sequence>) this; return entrySequence.collect(constructor, Maps::put); } /** * Convert this {@code Sequence} of into a {@link Map}, using the given key mapper {@link Function} and value * mapper * {@link Function} to convert each element into a {@link Map} entry. */ default Map toMap(Function keyMapper, Function valueMapper) { return toMap(HashMap::new, keyMapper, valueMapper); } /** * Convert this {@code Sequence} of into a {@link Map} of the type determined by the given constructor, using the * given key mapper {@link Function} and value mapper {@link Function} to convert each element into a {@link Map} * entry. */ default , K, V> M toMap(Supplier constructor, Function keyMapper, Function valueMapper) { return collect(constructor, (result, element) -> result.put(keyMapper.apply(element), valueMapper.apply(element))); } /** * Convert this {@code Sequence} of {@link Map.Entry} into a {@link SortedMap}. * * @throws ClassCastException if this {@code Sequence} is not of {@link Map.Entry}. */ default SortedMap toSortedMap() { return toMap(TreeMap::new); } /** * Convert this {@code Sequence} into a {@link SortedMap}, using the given key mapper {@link Function} and value * mapper {@link Function} to convert each element into a {@link SortedMap} entry. */ default SortedMap toSortedMap(Function keyMapper, Function valueMapper) { return toMap(TreeMap::new, keyMapper, valueMapper); } /** * Collect this {@code Sequence} into a {@link Collection} of the type determined by the given constructor. */ default > U toCollection(Supplier constructor) { return collectInto(constructor.get()); } /** * Collect this {@code Sequence} into an arbitrary container using the given constructor and adder. */ default C collect(Supplier constructor, BiConsumer adder) { return collectInto(constructor.get(), adder); } /** * Collect this {@code Sequence} into an arbitrary container using the given {@link Collector}. */ default R collect(Collector collector) { A container = collect(collector.supplier(), collector.accumulator()); return collector.finisher().apply(container); } /** * Collect this {@code Sequence} into the given {@link Collection}. */ default > U collectInto(U collection) { collection.addAll(this); return collection; } /** * Collect this {@code Sequence} into the given container, using the given adder. */ default C collectInto(C result, BiConsumer adder) { forEach(each -> adder.accept(result, each)); return result; } /** * @return a {@link List} view of this {@code Sequence}, which is updated in real time as the backing store of the * {@code Sequence} changes. The list does not implement {@link RandomAccess} and is best accessed in sequence. The * list supports {@link List#add} only if the {@code Sequence} is backed by a list itself, otherwise it supports * removal only. * * @since 1.2 */ default List asList() { return Iterables.asList(this); } /** * Join this {@code Sequence} into a string. * * @since 1.2 */ default String join() { return join(""); } /** * Join this {@code Sequence} into a string separated by the given delimiter. */ default String join(String delimiter) { return join("", delimiter, ""); } /** * Join this {@code Sequence} into a string separated by the given delimiter, with the given prefix and suffix. */ default String join(String prefix, String delimiter, String suffix) { StringBuilder result = new StringBuilder(); result.append(prefix); boolean started = false; for (T each : this) { if (started) result.append(delimiter); else started = true; result.append(each); } result.append(suffix); return result.toString(); } /** * Reduce this {@code Sequence} into a single element by iteratively applying the given binary operator to * the current result and each element in this sequence. */ default Optional reduce(BinaryOperator operator) { return Iterators.reduce(iterator(), operator); } /** * Reduce this {@code Sequence} into a single element by iteratively applying the given binary operator to * the current result and each element in this sequence, starting with the given identity as the initial result. */ default T reduce(T identity, BinaryOperator operator) { return Iterators.reduce(iterator(), identity, operator); } /** * @return the first element of this {@code Sequence} or an empty {@link Optional} if there are no elements in the * {@code Sequence}. */ default Optional first() { return at(0); } /** * @return the last element of this {@code Sequence} or an empty {@link Optional} if there are no elements in the * {@code Sequence}. */ default Optional last() { return Iterators.last(iterator()); } /** * @return the element at the given index, or an empty {@link Optional} if the {@code Sequence} is smaller than the * index. * * @since 1.2 */ default Optional at(int index) { return Iterators.get(iterator(), index); } /** * @return the first element of this {@code Sequence} that matches the given predicate, or an empty * {@link Optional} * if there are no matching elements in the {@code Sequence}. * * @since 1.2 */ default Optional first(Predicate predicate) { return at(0, predicate); } /** * @return the last element of this {@code Sequence} the matches the given predicate, or an empty {@link Optional} * if there are no matching elements in the {@code Sequence}. * * @since 1.2 */ default Optional last(Predicate predicate) { return filter(predicate).last(); } /** * @return the element at the given index out of the elements matching the given predicate, or an empty {@link * Optional} if the {@code Sequence} of matching elements is smaller than the index. * * @since 1.2 */ default Optional at(int index, Predicate predicate) { return filter(predicate).at(index); } /** * @return the first element of this {@code Sequence} that is an instance of the given {@link Class}, or an empty * {@link Optional} if there are no matching elements in the {@code Sequence}. * * @since 1.2 */ default Optional first(Class target) { return at(0, target); } /** * @return the last element of this {@code Sequence} that is an instance of the given {@link Class}, or an empty * {@link Optional} if there are no matching elements in the {@code Sequence}. * * @since 1.2 */ @SuppressWarnings("unchecked") default Optional last(Class target) { return (Optional) last(target::isInstance); } /** * @return the element at the given index out of the elements that are instances of the given {@link Class}, or an * empty {@link Optional} if the {@code Sequence} of matching elements is smaller than the index. * * @since 1.2 */ @SuppressWarnings("unchecked") default Optional at(int index, Class target) { return (Optional) at(index, target::isInstance); } /** * Pair the elements of this {@code Sequence} into a sequence of overlapping {@link Entry} elements. Each entry * overlaps the value item with the key item of the next entry. If there is only one item in the sequence, the * first entry returned has that item as a key and null as the value. */ default Sequence> entries() { return () -> new PairingIterator>(iterator(), 1) { @Override protected Entry pair(T first, T second) { return Maps.entry(first, second); } }; } /** * Pair the elements of this {@code Sequence} into a sequence of {@link Pair} elements. Each pair overlaps the * second item with the first item of the next pair. If there is only one item in the list, the first pair returned * has a null as the second item. */ default Sequence> pairs() { return () -> new PairingIterator>(iterator(), 1) { @Override protected Pair pair(T first, T second) { return Pair.of(first, second); } }; } /** * Pair the elements of this {@code Sequence} into a sequence of {@link Entry} elements. Each entry is adjacent to * the next entry. If there is an uneven amount of items in the list, the final entry returned has a null as the * value item. */ default Sequence> adjacentEntries() { return () -> new PairingIterator>(iterator(), 2) { @Override protected Entry pair(T first, T second) { return Maps.entry(first, second); } }; } /** * Pair the elements of this {@code Sequence} into a sequence of {@link Pair} elements. Each pair is adjacent to * the next pair. If there is an uneven amount of items in the list, the final pair returned has a null as the * second item. */ default Sequence> adjacentPairs() { return () -> new PairingIterator>(iterator(), 2) { @Override protected Pair pair(T first, T second) { return Pair.of(first, second); } }; } /** * Converts a {@code Sequence} of {@link Pair}s of items into a {@link BiSequence}. Note the sequence must be of * {@link Pair} or a {@link ClassCastException} will occur when traversal is attempted. */ @SuppressWarnings("unchecked") default BiSequence toBiSequence() { Sequence> pairSequence = (Sequence>) this; return BiSequence.from(pairSequence); } /** * Converts a {@code Sequence} of {@link Map.Entry} items into an {@link EntrySequence}. Note the sequence must be * of {@link Map.Entry} or a {@link ClassCastException} will occur when traversal is attempted. */ @SuppressWarnings("unchecked") default EntrySequence toEntrySequence() { Sequence> entrySequence = (Sequence>) this; return EntrySequence.from(entrySequence); } /** * Window the elements of this {@code Sequence} into a sequence of {@code Sequence}s of elements, each with the * size of the given window. The first item in each sequence is the second item in the previous sequence. The final * sequence may be shorter than the window. This method is equivalent to {@code window(window, 1)}. */ default Sequence> window(int window) { return window(window, 1); } /** * Window the elements of this {@code Sequence} into a sequence of {@code Sequence}s of elements, each with the * size of the given window, stepping {@code step} elements between each window. If the given step is less than the * window size, the windows will overlap each other. If the step is larger than the window size, elements will be * skipped in between windows. */ default Sequence> window(int window, int step) { return () -> new WindowingIterator>(iterator(), window, step) { @Override protected Sequence toSequence(List list) { return ListSequence.from(list); } }; } /** * Batch the elements of this {@code Sequence} into a sequence of {@code Sequence}s of distinct elements, each with * the given batch size. This method is equivalent to {@code window(size, size)}. */ default Sequence> batch(int size) { return window(size, size); } /** * Batch the elements of this {@code Sequence} into a sequence of {@code Sequence}s of distinct elements, where the * given predicate determines where to split the lists of partitioned elements. The predicate is given the current * and next item in the iteration, and if it returns true a partition is created between the elements. */ default Sequence> batch(BiPredicate predicate) { return () -> new PredicatePartitioningIterator>(iterator(), predicate) { @Override protected Sequence toSequence(List list) { return ListSequence.from(list); } }; } /** * Split the elements of this {@code Sequence} into a sequence of {@code Sequence}s of distinct elements, around * the given element. The elements around which the sequence is split are not included in the result. * * @since 1.1 */ default Sequence> split(T element) { return () -> new SplittingIterator>(iterator(), element) { @Override protected Sequence toSequence(List list) { return ListSequence.from(list); } }; } /** * Split the elements of this {@code Sequence} into a sequence of {@code Sequence}s of distinct elements, where the * given predicate determines which elements to split the partitioned elements around. The elements matching the * predicate are not included in the result. * * @since 1.1 */ default Sequence> split(Predicate predicate) { return () -> new SplittingIterator>(iterator(), predicate) { @Override protected Sequence toSequence(List list) { return ListSequence.from(list); } }; } /** * Skip x number of steps in between each invocation of the iterator of this {@code Sequence}. */ default Sequence step(int step) { return () -> new SteppingIterator<>(iterator(), step); } /** * @return a {@code Sequence} where each item in this {@code Sequence} occurs only once, the first time it is * encountered. */ default Sequence distinct() { return () -> new DistinctIterator<>(iterator()); } /** * @return this {@code Sequence} sorted according to the natural order. Must be a (@code Sequence} of {@link * Comparable} or a {@link ClassCastException} is thrown during traversal. */ @SuppressWarnings("unchecked") default Sequence sorted() { return () -> Iterators.unmodifiable(Lists.sort((List) toList())); } /** * @return this {@code Sequence} sorted according to the given {@link Comparator}. */ default Sequence sorted(Comparator comparator) { return () -> Iterators.unmodifiable(Lists.sort(toList(), comparator)); } /** * @return the minimal element in this {@code Sequence} according to their natural order. Elements in the sequence * must all implement {@link Comparable} or a {@link ClassCastException} will be thrown at traversal. * * @since 1.2 */ @SuppressWarnings("unchecked") default Optional min() { return min((Comparator) Comparator.naturalOrder()); } /** * @return the maximum element in this {@code Sequence} according to their natural order. Elements in the sequence * must all implement {@link Comparable} or a {@link ClassCastException} will be thrown at traversal. * * @since 1.2 */ @SuppressWarnings("unchecked") default Optional max() { return max((Comparator) Comparator.naturalOrder()); } /** * @return the minimal element in this {@code Sequence} according to the given {@link Comparator}. */ default Optional min(Comparator comparator) { return reduce(minBy(comparator)); } /** * @return the maximum element in this {@code Sequence} according to the given {@link Comparator}. */ default Optional max(Comparator comparator) { return reduce(maxBy(comparator)); } /** * @return true if all elements in this {@code Sequence} satisfy the given predicate, false otherwise. */ default boolean all(Predicate predicate) { return Iterables.all(this, predicate); } /** * @return true if no elements in this {@code Sequence} satisfy the given predicate, false otherwise. */ default boolean none(Predicate predicate) { return Iterables.none(this, predicate); } /** * @return true if any element in this {@code Sequence} satisfies the given predicate, false otherwise. */ default boolean any(Predicate predicate) { return Iterables.any(this, predicate); } /** * @return true if all elements in this {@code Sequence} are instances of the given {@link Class}, false otherwise. * * @since 1.2 */ default boolean all(Class target) { return all(target::isInstance); } /** * @return true if no elements in this {@code Sequence} are instances of the given {@link Class}, false otherwise. * * @since 1.2 */ default boolean none(Class target) { return none(target::isInstance); } /** * @return true if any element in this {@code Sequence} is an instance of the given {@link Class}, false otherwise. * * @since 1.2 */ default boolean any(Class target) { return any(target::isInstance); } /** * Allow the given {@link Consumer} to see each element in this {@code Sequence} as it is traversed. */ default Sequence peek(Consumer action) { return () -> new PeekingIterator<>(iterator(), action); } /** * Allow the given {@link ObjIntConsumer} to see each element with its index as this {@code Sequence} is * traversed. * * @since 1.2.2 */ default Sequence peekIndexed(ObjIntConsumer action) { return () -> new IndexPeekingIterator<>(iterator(), action); } /** * Allow the given {@link BiConsumer} to see each and its following element in this {@code Sequence} as it is * traversed. In the last iteration, the following item will be null. * * @see #peekForward(Object, BiConsumer) */ default Sequence peekForward(BiConsumer action) { return peekForward(null, action); } /** * Allow the given {@link BiConsumer} to see each and its previous element in this {@code Sequence} as it is * traversed. In the first iteration, the previous item will be null. * * @see #peekBack(Object, BiConsumer) */ default Sequence peekBack(BiConsumer action) { return peekBack(null, action); } /** * Allow the given {@link BiConsumer} to see each and its following element in this {@code Sequence} as it is * traversed. In the last iteration, the following item will have the given replacement value. * * @see #peekForward(BiConsumer) */ default Sequence peekForward(T replacement, BiConsumer action) { return () -> new ForwardPeekingMappingIterator(iterator(), replacement) { @Override protected T mapNext(T next, T following) { action.accept(next, following); return next; } @Override protected T mapFollowing(boolean hasFollowing, T following) { return following; } }; } /** * Allow the given {@link BiConsumer} to see each and its previous element in this {@code Sequence} as it is * traversed. In the first iteration, the previous item will have the given replacement value. * * @see #peekBack(BiConsumer) */ default Sequence peekBack(T replacement, BiConsumer action) { return () -> new BackPeekingMappingIterator(iterator(), replacement) { @Override protected T map(T previous, T next) { action.accept(previous, next); return next; } }; } /** * Delimit each element in this {@code Sequence} with the given delimiter element. */ @SuppressWarnings("unchecked") default Sequence delimit(V delimiter) { return () -> new DelimitingIterator<>((Iterator) iterator(), Optional.empty(), Optional.of(delimiter), Optional.empty()); } /** * Delimit the elements in this {@code Sequence} with the given delimiter, prefix and suffix elements. */ @SuppressWarnings("unchecked") default Sequence delimit(V prefix, V delimiter, V suffix) { return () -> new DelimitingIterator<>((Iterator) iterator(), Optional.of(prefix), Optional.of(delimiter), Optional.of(suffix)); } /** * Prefix the elements in this {@code Sequence} with the given prefix element. */ @SuppressWarnings("unchecked") default Sequence prefix(V prefix) { return () -> new DelimitingIterator<>((Iterator) iterator(), Optional.of(prefix), Optional.empty(), Optional.empty()); } /** * Suffix the elements in this {@code Sequence} with the given suffix element. */ @SuppressWarnings("unchecked") default Sequence suffix(V suffix) { return () -> new DelimitingIterator<>((Iterator) iterator(), Optional.empty(), Optional.empty(), Optional.of(suffix)); } /** * Interleave the elements in this {@code Sequence} with those of the given {@link Iterable}, stopping when either * sequence finishes. The result is a {@code Sequence} of pairs of items, the left entry coming from this * sequence and the right entry from the given iterable. */ default Sequence> interleave(Iterable that) { return () -> new InterleavingPairingIterator<>(iterator(), that.iterator()); } /** * @return a {@code Sequence} which iterates over this {@code Sequence} in reverse order. */ default Sequence reverse() { return () -> new ReverseIterator<>(iterator()); } /** * @return a {@code Sequence} which iterates over this {@code Sequence} in random order. */ default Sequence shuffle() { return () -> Iterators.unmodifiable(Lists.shuffle(toList())); } /** * @return a {@code Sequence} which iterates over this {@code Sequence} in random order as determined by the given * random generator. */ default Sequence shuffle(Random random) { return () -> Iterators.unmodifiable(Lists.shuffle(toList(), random)); } /** * @return a {@code Sequence} which iterates over this {@code Sequence} in random order as determined by the given * random generator. A new instance of {@link Random} is created by the given supplier at the start of each * iteration. * * @since 1.2 */ default Sequence shuffle(Supplier randomSupplier) { return () -> Iterators.unmodifiable(Lists.shuffle(toList(), randomSupplier.get())); } /** * Convert this {@code Sequence} to a {@link CharSeq} using the given mapper function to map each element to a * {@code char}. * * @see #toInts(ToIntFunction) * @see #toLongs(ToLongFunction) * @see #toDoubles(ToDoubleFunction) * @see #map(Function) * @see #flatten(Function) * @see #flatten() */ default CharSeq toChars(ToCharFunction mapper) { return () -> CharIterator.from(iterator(), mapper); } /** * Convert this {@code Sequence} to an {@link IntSequence} using the given mapper function to map each element * to an {@code int}. * * @see #toChars(ToCharFunction) * @see #toLongs(ToLongFunction) * @see #toDoubles(ToDoubleFunction) * @see #map(Function) * @see #flatten(Function) * @see #flatten() */ default IntSequence toInts(ToIntFunction mapper) { return () -> IntIterator.from(iterator(), mapper); } /** * Convert this {@code Sequence} to a {@link LongSequence} using the given mapper function to map each element to a * {@code long}. * * @see #toChars(ToCharFunction) * @see #toInts(ToIntFunction) * @see #toDoubles(ToDoubleFunction) * @see #map(Function) * @see #flatten(Function) * @see #flatten() */ default LongSequence toLongs(ToLongFunction mapper) { return () -> LongIterator.from(iterator(), mapper); } /** * Convert this {@code Sequence} to a {@link DoubleSequence} using the given mapper function to map each element * to a {@code double}. * * @see #toChars(ToCharFunction) * @see #toInts(ToIntFunction) * @see #toLongs(ToLongFunction) * @see #map(Function) * @see #flatten(Function) * @see #flatten() */ default DoubleSequence toDoubles(ToDoubleFunction mapper) { return () -> DoubleIterator.from(iterator(), mapper); } /** * Repeat this {@code Sequence} forever, producing a sequence that never terminates unless the original sequence is * empty in which case the resulting sequence is also empty. */ default Sequence repeat() { return () -> new RepeatingIterator<>(this, -1); } /** * Repeat this {@code Sequence} the given number of times. */ default Sequence repeat(int times) { return () -> new RepeatingIterator<>(this, times); } /** * Tests each pair of items in the sequence and swaps any two items which match the given predicate. */ default Sequence swap(BiPredicate swapper) { return () -> new SwappingIterator<>(iterator(), swapper); } /** * @return a {@link BiSequence} of this sequence paired up with the index of each element. */ default BiSequence index() { return () -> new DelegatingMappingIterator>(iterator()) { private int index; @Override public Pair next() { return Pair.of(index++, iterator.next()); } }; } /** * Perform the given action for each element in this {@code Sequence}, with the index of each element passed as the * second parameter in the action. * * @since 1.2 */ default void forEachIndexed(ObjIntConsumer action) { int index = 0; for (T each : this) action.accept(each, index++); } }