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 extends T> 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 extends T> 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 extends T> 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 extends T> 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 extends Supplier extends T>> supplierSupplier) {
return () -> {
Supplier extends T> 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 super T, ? extends S> f, Function super S, ? extends T> 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 super T> 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 super T> 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 super T, ? extends U> 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 super T, ? extends U> mapper, Function super U, ? extends T>
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 super T, ? extends U> 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 super T, ? super T, ? extends U> 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 super T, ? super T, ? extends U> 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 super T, ? super T, ? extends U> 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 super T, ? super T, ? extends U> 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 super T> 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 super T> 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 extends U> 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 super T, ? super T> 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 super T, ? super T> 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 super T, ? super T> 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 super T, ? super T> 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 extends T> 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 extends T> 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 super T, ? extends Iterable> 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 extends A[]> 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 extends List> 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 extends S> 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 extends M> 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 super T, ? extends K> keyMapper,
Function super T, ? extends V> 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 extends M> constructor,
Function super T, ? extends K> keyMapper,
Function super T, ? extends V> 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 super T, ? extends K> keyMapper,
Function super T, ? extends V> 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 extends U> constructor) {
return collectInto(constructor.get());
}
/**
* Collect this {@code Sequence} into an arbitrary container using the given constructor and adder.
*/
default C collect(Supplier extends C> constructor, BiConsumer super C, ? super T> 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 super C, ? super T> 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 super T> 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 super T> 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 super T> 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 extends U> 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 extends U> 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 extends U> 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 super T, ? super T> 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 super T> 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 super T> 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 super T> comparator) {
return reduce(minBy(comparator));
}
/**
* @return the maximum element in this {@code Sequence} according to the given {@link Comparator}.
*/
default Optional max(Comparator super T> comparator) {
return reduce(maxBy(comparator));
}
/**
* @return true if all elements in this {@code Sequence} satisfy the given predicate, false otherwise.
*/
default boolean all(Predicate super T> 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 super T> 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 super T> 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 super T> 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 super T> 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 super T, ? super T> 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 super T, ? super T> 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 super T, ? super T> 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 super T, ? super T> 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