![JAR search and dependency download from the Maven repository](/logo.png)
org.d2ab.sequence.EntrySequence 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.Lists;
import org.d2ab.collection.Maps;
import org.d2ab.function.*;
import org.d2ab.function.chars.ToCharBiFunction;
import org.d2ab.function.chars.ToCharFunction;
import org.d2ab.iterable.ChainingIterable;
import org.d2ab.iterable.Iterables;
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.Arrayz;
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 java.util.stream.StreamSupport;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyIterator;
/**
* An {@link Iterable} sequence of {@link Entry} elements with {@link Stream}-like operations for refining,
* transforming and collating the list of {@link Entry} elements.
*/
@FunctionalInterface
public interface EntrySequence extends Iterable> {
/**
* Create an empty {@code EntrySequence} with no items.
*
* @see #of(Entry)
* @see #of(Entry...)
* @see #ofEntry(Object, Object)
* @see #ofEntries(Object...)
* @see #from(Iterable)
*/
static EntrySequence empty() {
return once(emptyIterator());
}
/**
* Create an {@code EntrySequence} with one {@link Entry}.
*
* @see #of(Entry...)
* @see #ofEntry(Object, Object)
* @see #ofEntries(Object...)
* @see #from(Iterable)
*/
static EntrySequence of(Entry item) {
return from(Collections.singleton(item));
}
/**
* Create an {@code EntrySequence} with the given {@link Entry} list.
*
* @see #of(Entry)
* @see #ofEntry(Object, Object)
* @see #ofEntries(Object...)
* @see #from(Iterable)
*/
@SafeVarargs
static EntrySequence of(Entry... items) {
return from(asList(items));
}
/**
* Create an {@code EntrySequence} with one {@link Entry} of the given key and value.
*
* @see #ofEntries(Object...)
* @see #of(Entry)
* @see #of(Entry...)
* @see #from(Iterable)
*/
static EntrySequence ofEntry(K left, V right) {
return of(Maps.entry(left, right));
}
/**
* Create an {@code EntrySequence} with an {@link Entry} list created from the given keys and values in sequence in
* the input array.
*
* @throws IllegalArgumentException if the array of keys and values is not of even length.
* @see #ofEntry(Object, Object)
* @see #of(Entry)
* @see #of(Entry...)
* @see #from(Iterable)
*/
@SuppressWarnings("unchecked")
static EntrySequence ofEntries(Object... os) {
if (os.length % 2 != 0)
throw new IllegalArgumentException("Expected an even set of objects, but got: " + os.length);
List> entries = new ArrayList<>();
for (int i = 0; i < os.length; i += 2)
entries.add(Maps.entry((K) os[i], (V) os[i + 1]));
return from(entries);
}
/**
* Create an {@code EntrySequence} from an {@link Iterable} of entries.
*
* @see #of(Entry)
* @see #of(Entry...)
* @see #from(Iterable...)
* @see #cache(Iterable)
*/
static EntrySequence from(Iterable> iterable) {
return iterable::iterator;
}
/**
* Create a concatenated {@code EntrySequence} from several {@link Iterable}s of entries which are concatenated
* together to form the stream of entries in the {@code EntrySequence}.
*
* @see #of(Entry)
* @see #of(Entry...)
* @see #from(Iterable)
*/
@SafeVarargs
static EntrySequence from(Iterable>... iterables) {
return () -> new ChainingIterator<>(iterables);
}
/**
* Create a once-only {@code EntrySequence} from an {@link Iterator} of entries. Note that {@code EntrySequence}s
* created from {@link Iterator}s cannot be passed over more than once. Further attempts will register the
* {@code EntrySequence} as empty.
*
* @see #of(Entry)
* @see #of(Entry...)
* @see #from(Iterable)
* @see #cache(Iterator)
* @since 1.1
*/
static EntrySequence once(Iterator> iterator) {
return from(Iterables.once(iterator));
}
/**
* Create a once-only {@code EntrySequence} from a {@link Stream} of entries. Note that {@code EntrySequence}s
* created from {@link Stream}s cannot be passed over more than once. Further attempts will register the
* {@code EntrySequence} as empty.
*
* @see #of(Entry)
* @see #of(Entry...)
* @see #from(Iterable)
* @see #once(Iterator)
* @see #cache(Stream)
* @since 1.1
*/
static EntrySequence once(Stream> stream) {
return once(stream.iterator());
}
/**
* Create a once-only {@code EntrySequence} from an {@link Iterator} of entries. Note that {@code EntrySequence}s
* created from {@link Iterator}s cannot be passed over more than once. Further attempts will register the
* {@code EntrySequence} as empty.
*
* @see #of(Entry)
* @see #of(Entry...)
* @see #from(Iterable)
* @see #cache(Iterator)
* @deprecated Use {@link #once(Iterator)} instead.
*/
@Deprecated
static EntrySequence from(Iterator> iterator) {
return once(iterator);
}
/**
* Create a once-only {@code EntrySequence} from a {@link Stream} of entries. Note that {@code EntrySequence}s
* created from {@link Stream}s cannot be passed over more than once. Further attempts will register the
* {@code EntrySequence} as empty.
*
* @see #of(Entry)
* @see #of(Entry...)
* @see #from(Iterable)
* @see #once(Iterator)
* @see #cache(Stream)
* @deprecated Use {@link #once(Stream)} instead.
*/
@Deprecated
static EntrySequence from(Stream> stream) {
return once(stream);
}
/**
* Create an {@code EntrySequence} of {@link Map.Entry} key/value items from a {@link Map} of items. The resulting
* {@code EntrySequence} can be mapped using {@link Pair} items, which implement {@link Map.Entry} and can thus be
* processed as part of the {@code EntrySequence}'s transformation steps.
*
* @see #of
* @see #from(Iterable)
*/
static EntrySequence from(Map map) {
return from(map.entrySet());
}
/**
* Create an {@code EntrySequence} with a cached copy of an {@link Iterable} of entries.
*
* @see #cache(Iterator)
* @see #cache(Stream)
* @see #from(Iterable)
* @since 1.1
*/
static EntrySequence cache(Iterable> iterable) {
return from(Iterables.toList(iterable));
}
/**
* Create an {@code EntrySequence} with a cached copy of an {@link Iterator} of entries.
*
* @see #cache(Iterable)
* @see #cache(Stream)
* @see #once(Iterator)
* @since 1.1
*/
static EntrySequence cache(Iterator> iterator) {
return from(Iterators.toList(iterator));
}
/**
* Create an {@code EntrySequence} with a cached copy of a {@link Stream} of entries.
*
* @see #cache(Iterable)
* @see #cache(Iterator)
* @see #once(Stream)
* @since 1.1
*/
static EntrySequence cache(Stream> stream) {
return from(stream.collect(Collectors.toList()));
}
/**
* @return an infinite {@code EntrySequence} generated by repeatedly calling the given supplier. The returned
* {@code EntrySequence} never terminates naturally.
*
* @see #recurse(Entry, UnaryOperator)
* @see #recurse(Object, Object, BiFunction)
* @see #endingAt(Entry)
* @see #until(Entry)
*/
static EntrySequence generate(Supplier> supplier) {
return () -> (InfiniteIterator>) supplier::get;
}
/**
* @return an infinite {@code EntrySequence} where each {@link #iterator()} is generated by polling for a supplier
* and then using it to generate the sequence of entries. The sequence never terminates.
*
* @see #generate(Supplier)
* @see #recurse(Entry, UnaryOperator)
* @see #endingAt(Entry)
* @see #until(Entry)
*/
static EntrySequence multiGenerate(Supplier extends Supplier extends Entry>>
supplierSupplier) {
return () -> {
Supplier extends Entry> supplier = supplierSupplier.get();
return (InfiniteIterator>) supplier::get;
};
}
/**
* Returns an {@code EntrySequence} produced by recursively applying the given operation to the given seeds, which
* form the first element of the sequence, the second being {@code f(keySeed, valueSeed)}, the third
* {@code f(f(keySeed, valueSeed))} and so on. The returned {@code EntrySequence} never terminates naturally.
*
* @return an {@code EntrySequence} produced by recursively applying the given operation to the given seed
*
* @see #recurse(Entry, UnaryOperator)
* @see #generate(Supplier)
* @see #endingAt(Entry)
* @see #until(Entry)
*/
static EntrySequence recurse(K keySeed, V valueSeed, BiFunction> op) {
return recurse(Maps.entry(keySeed, valueSeed), Maps.asUnaryOperator(op));
}
/**
* Returns an {@code EntrySequence} produced by recursively applying the given operation to the given seed, which
* form the first element of the sequence, the second being {@code f(seed)}, the third {@code f(f(seed))} and so
* on. The returned {@code EntrySequence} never terminates naturally.
*
* @return an {@code EntrySequence} produced by recursively applying the given operation to the given seed
*
* @see #recurse(Entry, UnaryOperator)
* @see #recurse(Object, Object, BiFunction)
* @see #generate(Supplier)
* @see #endingAt(Entry)
* @see #until(Entry)
*/
static EntrySequence recurse(Entry entry, UnaryOperator> unaryOperator) {
return () -> new RecursiveIterator<>(entry, unaryOperator);
}
/**
* Returns an {@code EntrySequence} produced by recursively applying the given mapper {@code f} and incrementer
* {@code g} operations to the given seeds, the first element being {@code f(keySeed, valueSeed)}, the second
* being {@code f(g(f(keySeed, valueSeed)))}, the third {@code f(g(f(g(f(keySeed, valueSeed)))))} and so on.
* The returned {@code EntrySequence} never terminates naturally.
*
* @param f a mapper function for producing elements that are to be included in the sequence, the first being
* f(keySeed, valueSeed)
* @param g an incrementer function for producing the next unmapped element to be included in the sequence,
* applied to the first mapped element f(keySeed, valueSeed) to produce the second unmapped value
*
* @return an {@code EntrySequence} produced by recursively applying the given mapper and incrementer operations
* to the
* given seeds
*
* @see #recurse(Entry, UnaryOperator)
* @see #recurse(Object, Object, BiFunction)
* @see #endingAt(Entry)
* @see #until(Entry)
*/
static EntrySequence recurse(K keySeed, V valueSeed,
BiFunction super K, ? super V, ? extends Entry> f,
BiFunction super KK, ? super VV, ? extends Entry> g) {
Function, Entry> f1 = Maps.asFunction(f);
Function, Entry> g1 = Maps.asFunction(g);
return recurse(f.apply(keySeed, valueSeed), f1.compose(g1)::apply);
}
/**
* Map the entries in this {@code EntrySequence} to another set of entries specified by the given {@code mapper}
* function.
*
* @see #map(Function)
* @see #map(Function, Function)
* @see #flatten(Function)
*/
default EntrySequence map(BiFunction super K, ? super V, ? extends Entry> mapper) {
return map(Maps.asFunction(mapper));
}
/**
* Map the entries in this {@code EntrySequence} to another set of entries specified by the given {@code mapper}
* function.
*
* @see #map(BiFunction)
* @see #map(Function, Function)
* @see #flatten(Function)
*/
default EntrySequence map(Function super Entry, ? extends Entry> mapper) {
return () -> new MappingIterator<>(iterator(), mapper);
}
/**
* Map the entries in this {@code EntrySequence} to another set of entries specified by the given {@code keyMapper}
* amd {@code valueMapper} functions.
*
* @see #map(BiFunction)
* @see #map(Function)
* @see #flatten(Function)
*/
default EntrySequence map(Function super K, ? extends KK> keyMapper,
Function super V, ? extends VV> valueMapper) {
return map(Maps.asFunction(keyMapper, valueMapper));
}
/**
* Map the entries in this {@code EntrySequence} to another set of entries specified by the given {@code mapper}
* function. In addition to the current entry, the mapper has access to the index of each entry.
*
* @see #map(Function)
* @see #flatten(Function)
* @since 1.2
*/
default EntrySequence mapIndexed(
ObjLongFunction super Entry, ? extends Entry> mapper) {
return () -> new IndexingMappingIterator<>(iterator(), mapper);
}
/**
* Map the entries in this {@code EntrySequence} to another set of entries specified by the given {@code mapper}
* function. In addition to the current entry, the mapper has access to the index of each entry.
*
* @see #map(Function)
* @see #flatten(Function)
* @since 1.2
*/
default EntrySequence mapIndexed(
ObjObjLongFunction super K, ? super V, ? extends Entry> mapper) {
return mapIndexed((e, i) -> mapper.apply(e.getKey(), e.getValue(), i));
}
/**
* Skip a set number of steps in this {@code EntrySequence}.
*/
default EntrySequence skip(int skip) {
return () -> new SkippingIterator<>(iterator(), skip);
}
/**
* Skip a set number of steps at the end of this {@code EntrySequence}.
*
* @since 1.1
*/
default EntrySequence skipTail(long skip) {
if (skip == 0)
return this;
return () -> new TailSkippingIterator<>(iterator(), (int) skip);
}
/**
* Limit the maximum number of results returned by this {@code EntrySequence}.
*/
default EntrySequence limit(int limit) {
return () -> new LimitingIterator<>(iterator(), limit);
}
/**
* Filter the elements in this {@code EntrySequence}, keeping only the elements that match the given
* {@link BiPredicate}.
*/
default EntrySequence filter(BiPredicate super K, ? super V> predicate) {
return filter(Maps.asPredicate(predicate));
}
/**
* Filter the elements in this {@code EntrySequence}, keeping only the entries that match the given
* {@link Predicate}.
*/
default EntrySequence filter(Predicate super Entry> predicate) {
return () -> new FilteringIterator<>(iterator(), predicate);
}
/**
* Filter the entries in this {@code EntrySequence}, keeping only the elements that match the given
* {@link ObjLongPredicate}, which is passed the current entry and its index in the sequence.
*
* @since 1.2
*/
default EntrySequence filterIndexed(ObjLongPredicate super Entry> predicate) {
return () -> new IndexedFilteringIterator<>(iterator(), predicate);
}
/**
* Filter the entries in this {@code EntrySequence}, keeping only the elements that match the given
* {@link ObjLongPredicate}, which is passed the current entry and its index in the sequence.
*
* @since 1.2
*/
default EntrySequence filterIndexed(ObjObjLongPredicate super K, ? super V> predicate) {
return filterIndexed((e, i) -> predicate.test(e.getKey(), e.getValue(), i));
}
/**
* @return a {@code EntrySequence} containing only the entries found in the given target array.
*
* @since 1.2
*/
@SuppressWarnings("unchecked")
default EntrySequence including(Entry... entries) {
return filter(e -> Arrayz.contains(entries, e));
}
/**
* @return a {@code EntrySequence} containing only the entries found in the given target iterable.
*
* @since 1.2
*/
default EntrySequence including(Iterable extends Entry> entries) {
return filter(e -> Iterables.contains(entries, e));
}
/**
* @return a {@code EntrySequence} containing only the entries not found in the given target array.
*
* @since 1.2
*/
@SuppressWarnings("unchecked")
default EntrySequence excluding(Entry... entries) {
return filter(e -> !Arrayz.contains(entries, e));
}
/**
* @return a {@code EntrySequence} containing only the entries not found in the given target iterable.
*
* @since 1.2
*/
default EntrySequence excluding(Iterable extends Entry> entries) {
return filter(e -> !Iterables.contains(entries, e));
}
/**
* @return a {@link Sequence} of the {@link Entry} elements in this {@code EntrySequence} flattened into their
* key and value components strung together.
*/
default Sequence flatten() {
return toSequence().flatten();
}
/**
* Flatten the elements in this {@code EntrySequence} according to the given mapper {@link BiFunction}. The
* resulting {@code EntrySequence} contains the elements that is the result of applying the mapper
* {@link BiFunction} to each element, appended together inline as a single {@code EntrySequence}.
*
* @see #flatten(Function)
* @see #flattenKeys(Function)
* @see #flattenValues(Function)
* @see #map(BiFunction)
* @see #map(Function)
*/
default EntrySequence flatten(
BiFunction super K, ? super V, ? extends Iterable>> mapper) {
return flatten(Maps.asFunction(mapper));
}
/**
* Flatten the elements in this {@code EntrySequence} according to the given mapper {@link Function}. The
* resulting {@code EntrySequence} contains the entries that is the result of applying the mapper
* {@link Function} to each entry, appended together inline as a single {@code EntrySequence}.
*
* @see #flatten(BiFunction)
* @see #flattenKeys(Function)
* @see #flattenValues(Function)
* @see #map(BiFunction)
* @see #map(Function)
*/
default EntrySequence flatten(
Function super Entry, ? extends Iterable>> mapper) {
ChainingIterable> result = new ChainingIterable<>();
toSequence(mapper).forEach(result::append);
return result::iterator;
}
/**
* Flatten the keys of each entry in this sequence, applying multiples of keys returned by the given
* mapper to the same value of each entry.
*
* @see #flattenValues(Function)
* @see #flatten(Function)
* @see #flatten(BiFunction)
*/
default EntrySequence flattenKeys(Function super Entry, ? extends Iterable> mapper) {
return () -> new KeyFlatteningEntryIterator<>(iterator(), mapper);
}
/**
* Flatten the values of each entry in this sequence, applying multiples of values returned by the given
* mapper to the same key of each entry.
*
* @see #flattenKeys(Function)
* @see #flatten(Function)
* @see #flatten(BiFunction)
*/
default EntrySequence flattenValues(Function super Entry, ? extends Iterable> mapper) {
return () -> new ValueFlatteningEntryIterator<>(iterator(), mapper);
}
/**
* Terminate this {@code EntrySequence} just before the given element is encountered, not including the element in
* the {@code EntrySequence}.
*
* @see #until(Predicate)
* @see #endingAt(Entry)
* @see #generate(Supplier)
* @see #recurse
* @see #repeat()
*/
default EntrySequence until(Entry terminal) {
return () -> new ExclusiveTerminalIterator<>(iterator(), terminal);
}
/**
* Terminate this {@code EntrySequence} when the given element is encountered, including the element as the last
* element in the {@code EntrySequence}.
*
* @see #endingAt(Predicate)
* @see #until(Entry)
* @see #generate(Supplier)
* @see #recurse(Entry, UnaryOperator)
* @see #repeat()
*/
default EntrySequence endingAt(Entry terminal) {
return () -> new InclusiveTerminalIterator<>(iterator(), terminal);
}
/**
* Terminate this {@code EntrySequence} just before the entry with the given key and value is encountered,
* not including the entry in the {@code EntrySequence}.
*
* @see #until(Entry)
* @see #until(Predicate)
* @see #until(BiPredicate)
* @see #endingAt(Entry)
* @see #generate(Supplier)
* @see #recurse(Entry, UnaryOperator)
* @see #repeat()
*/
default EntrySequence until(K key, V value) {
return until(Maps.entry(key, value));
}
/**
* Terminate this {@code EntrySequence} when the entry the given key and value is encountered,
* including the element as the last element in the {@code EntrySequence}.
*
* @see #endingAt(Entry)
* @see #endingAt(Predicate)
* @see #endingAt(BiPredicate)
* @see #until(Entry)
* @see #generate(Supplier)
* @see #recurse(Entry, UnaryOperator)
* @see #repeat()
*/
default EntrySequence endingAt(K key, V value) {
return endingAt(Maps.entry(key, value));
}
/**
* Terminate this {@code EntrySequence} just before the given predicate is satisfied, not including the element
* that
* satisfies the predicate in the {@code EntrySequence}.
*
* @see #until(Predicate)
* @see #until(Object, Object)
* @see #until(Entry)
* @see #endingAt(Predicate)
* @see #generate(Supplier)
* @see #recurse(Entry, UnaryOperator)
* @see #repeat()
*/
default EntrySequence until(BiPredicate super K, ? super V> terminal) {
return until(Maps.asPredicate(terminal));
}
/**
* Terminate this {@code EntrySequence} when the given predicate is satisfied, including the element that satisfies
* the predicate as the last element in the {@code EntrySequence}.
*
* @see #endingAt(Predicate)
* @see #endingAt(Object, Object)
* @see #endingAt(Entry)
* @see #until(Predicate)
* @see #generate(Supplier)
* @see #recurse(Entry, UnaryOperator)
* @see #repeat()
*/
default EntrySequence endingAt(BiPredicate super K, ? super V> terminal) {
return endingAt(Maps.asPredicate(terminal));
}
/**
* Terminate this {@code EntrySequence} just before the given predicate is satisfied, not including the element
* that
* satisfies the predicate in the {@code EntrySequence}.
*
* @see #until(BiPredicate)
* @see #until(Entry)
* @see #endingAt(Predicate)
* @see #generate(Supplier)
* @see #recurse(Entry, UnaryOperator)
* @see #repeat()
*/
default EntrySequence until(Predicate super Entry> terminal) {
return () -> new ExclusiveTerminalIterator<>(iterator(), terminal);
}
/**
* Terminate this {@code EntrySequence} when the given predicate is satisfied, including the element that satisfies
* the predicate as the last element in the {@code EntrySequence}.
*
* @see #endingAt(BiPredicate)
* @see #endingAt(Entry)
* @see #until(Predicate)
* @see #generate(Supplier)
* @see #recurse(Entry, UnaryOperator)
* @see #repeat()
*/
default EntrySequence endingAt(Predicate super Entry> terminal) {
return () -> new InclusiveTerminalIterator<>(iterator(), terminal);
}
/**
* Begin this {@code EntrySequence} just after the given Entry is encountered, not including the entry in the
* {@code EntrySequence}.
*
* @see #startingAfter(Predicate)
* @see #startingAfter(BiPredicate)
* @see #startingFrom(Entry)
* @since 1.1
*/
default EntrySequence startingAfter(Entry element) {
return () -> new ExclusiveStartingIterator<>(iterator(), element);
}
/**
* Begin this {@code EntrySequence} when the given Entry is encountered, including the entry as the first element
* in the {@code EntrySequence}.
*
* @see #startingFrom(Predicate)
* @see #startingFrom(BiPredicate)
* @see #startingAfter(Entry)
* @since 1.1
*/
default EntrySequence startingFrom(Entry element) {
return () -> new InclusiveStartingIterator<>(iterator(), element);
}
/**
* Begin this {@code EntrySequence} just after the given predicate is satisfied, not including the entry that
* satisfies the predicate in the {@code EntrySequence}.
*
* @see #startingAfter(BiPredicate)
* @see #startingAfter(Entry)
* @see #startingFrom(Predicate)
* @since 1.1
*/
default EntrySequence startingAfter(Predicate super Entry> predicate) {
return () -> new ExclusiveStartingIterator<>(iterator(), predicate);
}
/**
* Begin this {@code EntrySequence} when the given predicate is satisfied, including the entry that satisfies
* the predicate as the first element in the {@code EntrySequence}.
*
* @see #startingFrom(BiPredicate)
* @see #startingFrom(Entry)
* @see #startingAfter(Predicate)
* @since 1.1
*/
default EntrySequence startingFrom(Predicate super Entry> predicate) {
return () -> new InclusiveStartingIterator<>(iterator(), predicate);
}
/**
* Begin this {@code EntrySequence} just after the given predicate is satisfied, not including the entry that
* satisfies the predicate in the {@code EntrySequence}.
*
* @see #startingAfter(Predicate)
* @see #startingAfter(Entry)
* @see #startingFrom(Predicate)
* @since 1.1
*/
default EntrySequence startingAfter(BiPredicate super K, ? super V> predicate) {
return startingAfter(Maps.asPredicate(predicate));
}
/**
* Begin this {@code EntrySequence} when the given predicate is satisfied, including the entry that satisfies
* the predicate as the first element in the {@code EntrySequence}.
*
* @see #startingFrom(Predicate)
* @see #startingFrom(Entry)
* @see #startingAfter(Predicate)
* @since 1.1
*/
default EntrySequence startingFrom(BiPredicate super K, ? super V> predicate) {
return startingFrom(Maps.asPredicate(predicate));
}
/**
* Collect the entries in this {@code EntrySequence} into an array.
*/
default Entry[] toArray() {
return toArray(Entry[]::new);
}
/**
* Collect the entries in this {@code EntrySequence} into an array of the type determined by the given array
* constructor.
*/
default Entry[] toArray(IntFunction[]> constructor) {
List> list = toList();
@SuppressWarnings("unchecked")
Entry[] array = list.toArray(constructor.apply(list.size()));
return array;
}
/**
* Collect the entries in this {@code EntrySequence} into a {@link List}.
*/
default List> toList() {
return toList(ArrayList::new);
}
/**
* Collect the entries in this {@code EntrySequence} into a {@link List} of the type determined by the given
* constructor.
*/
default List> toList(Supplier>> constructor) {
return toCollection(constructor);
}
/**
* Collect the entries in this {@code EntrySequence} into a {@link Set}.
*/
default Set> toSet() {
return toSet(HashSet::new);
}
/**
* Collect the entries in this {@code EntrySequence} into a {@link Set} of the type determined by the given
* constructor.
*/
default >> S toSet(Supplier extends S> constructor) {
return toCollection(constructor);
}
/**
* Collect the entries in this {@code EntrySequence} into a {@link SortedSet}.
*/
default SortedSet> toSortedSet() {
return toSet(TreeSet::new);
}
/**
* Collect the entries in this {@code EntrySequence} into a {@link Map}.
*/
default Map toMap() {
return toMap(HashMap::new);
}
/**
* Collect the entries in this {@code EntrySequence} into a {@link Map} of the type determined by the given
* constructor.
*/
default > M toMap(Supplier extends M> constructor) {
return collect(constructor, Maps::put);
}
/**
* Collect the entries in this {@code EntrySequence} into a {@link SortedMap}.
*/
default SortedMap toSortedMap() {
return toMap(TreeMap::new);
}
/**
* Collect this {@code EntrySequence} into a {@link Collection} of the type determined by the given constructor.
*/
default >> C toCollection(Supplier extends C> constructor) {
return collect(constructor, Collection::add);
}
/**
* Collect this {@code EntrySequence} into an arbitrary container using the given constructor and adder.
*/
default C collect(Supplier extends C> constructor, BiConsumer super C, ? super Entry> adder) {
return collectInto(constructor.get(), adder);
}
/**
* Collect this {@code EntrySequence} into an arbitrary container using the given {@link Collector}.
*/
default S collect(Collector, R, S> collector) {
R intermediary = collect(collector.supplier(), collector.accumulator());
return collector.finisher().apply(intermediary);
}
/**
* Collect this {@code EntrySequence} into the given {@link Collection}.
*/
default >> U collectInto(U collection) {
return collectInto(collection, Collection::add);
}
/**
* Collect this {@code EntrySequence} into the given container, using the given adder.
*/
default C collectInto(C result, BiConsumer super C, ? super Entry> adder) {
forEach(entry -> adder.accept(result, entry));
return result;
}
/**
* Join this {@code EntrySequence} into a string separated by the given delimiter.
*/
default String join(String delimiter) {
return join("", delimiter, "");
}
/**
* Join this {@code EntrySequence} 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 first = true;
for (Entry each : this) {
if (first)
first = false;
else
result.append(delimiter);
result.append(each);
}
result.append(suffix);
return result.toString();
}
/**
* Reduce this {@code EntrySequence} into a single element by iteratively applying the given binary operator to
* the current result and each entry in this sequence.
*/
default Optional> reduce(BinaryOperator> operator) {
return Iterators.reduce(iterator(), operator);
}
/**
* Reduce this {@code EntrySequence} into a single element by iteratively applying the given function to
* the current result and each entry in this sequence. The function is passed the key and value of the result,
* followed by the keys and values of the current entry, respectively.
*/
default Optional> reduce(QuaternaryFunction> operator) {
return reduce(Maps.asBinaryOperator(operator));
}
/**
* Reduce this {@code EntrySequence} into a single element by iteratively applying the given binary operator to
* the current result and each entry in this sequence, starting with the given identity as the initial result.
*/
default Entry reduce(Entry identity, BinaryOperator> operator) {
return Iterators.reduce(iterator(), identity, operator);
}
/**
* Reduce this {@code EntrySequence} into a single element by iteratively applying the given binary operator to
* the current result and each entry in this sequence, starting with the given identity as the initial result.
* The function is passed the key and value of the result, followed by the keys and values of the current entry,
* respectively.
*/
default Entry reduce(K key, V value, QuaternaryFunction> operator) {
return reduce(Maps.entry(key, value), Maps.asBinaryOperator(operator));
}
/**
* @return the first entry of this {@code EntrySequence} or an empty {@link Optional} if there are no entries in
* the {@code EntrySequence}.
*/
default Optional> first() {
return get(0);
}
/**
* @return the second entry of this {@code EntrySequence} or an empty {@link Optional} if there are one or less
* entries in the {@code EntrySequence}.
*/
default Optional> second() {
return get(1);
}
/**
* @return the third entry of this {@code EntrySequence} or an empty {@link Optional} if there are two or less
* entries in the {@code EntrySequence}.
*/
default Optional> third() {
return get(2);
}
/**
* @return the element at the given index, or an empty {@link Optional} if the {@code EntrySequence} is smaller
* than the index.
*/
default Optional> get(long index) {
return Iterators.get(iterator(), index);
}
/**
* @return the last entry of this {@code EntrySequence} or an empty {@link Optional} if there are no entries in
* the {@code EntrySequence}.
*/
default Optional> last() {
return Iterators.last(iterator());
}
/**
* Window the elements of this {@code EntrySequence} into a {@link Sequence} of {@code EntrySequence}s of entrues,
* 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 EntrySequence} into a sequence of {@code EntrySequence}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, EntrySequence>(iterator(), window, step) {
@Override
protected EntrySequence toSequence(List> list) {
return EntrySequence.from(list);
}
};
}
/**
* Batch the elements of this {@code EntrySequence} into a sequence of {@code EntrySequence}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 EntrySequence} into a sequence of {@link EntrySequence}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 Entry, ? super Entry> predicate) {
return () -> new PredicatePartitioningIterator, EntrySequence>(iterator(), predicate) {
@Override
protected EntrySequence toSequence(List> list) {
return EntrySequence.from(list);
}
};
}
/**
* Batch the elements of this {@code EntrySequence} into a sequence of {@link EntrySequence}s of distinct elements,
* where the given predicate determines where to split the lists of partitioned elements. The predicate is given
* the keys and values of the current and next items in the iteration, and if it returns true a partition is
* created between the elements.
*/
default Sequence> batch(
QuaternaryPredicate super K, ? super V, ? super K, ? super V> predicate) {
return batch((e1, e2) -> predicate.test(e1.getKey(), e1.getValue(), e2.getKey(), e2.getValue()));
}
/**
* Split the elements of this {@code EntrySequence} into a sequence of {@code EntrySequence}s of distinct elements,
* around the given element. The elements around which the sequence is split are not included in the result.
*/
default Sequence> split(Entry element) {
return () -> new SplittingIterator, EntrySequence>(iterator(), element) {
@Override
protected EntrySequence toSequence(List> list) {
return EntrySequence.from(list);
}
};
}
/**
* Split the elements of this {@code EntrySequence} into a sequence of {@code EntrySequence}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.
*/
default Sequence> split(Predicate super Entry> predicate) {
return () -> new SplittingIterator, EntrySequence>(iterator(), predicate) {
@Override
protected EntrySequence toSequence(List> list) {
return EntrySequence.from(list);
}
};
}
/**
* Split the elements of this {@code EntrySequence} into a sequence of {@code EntrySequence}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.
*/
default Sequence> split(BiPredicate super K, ? super V> predicate) {
return split(Maps.asPredicate(predicate));
}
/**
* Skip x number of steps in between each invocation of the iterator of this {@code EntrySequence}.
*/
default EntrySequence step(int step) {
return () -> new SteppingIterator<>(iterator(), step);
}
/**
* @return an {@code EntrySequence} where each item in this {@code EntrySequence} occurs only once, the first time
* it is encountered.
*/
default EntrySequence distinct() {
return () -> new DistinctIterator<>(iterator());
}
/**
* @return this {@code EntrySequence} sorted according to the natural order.
*/
default EntrySequence sorted() {
return () -> Iterators.unmodifiable(Lists.sort((List) toList()));
}
/**
* @return this {@code EntrySequence} sorted according to the given {@link Comparator}.
*/
default EntrySequence sorted(Comparator super Entry extends K, ? extends V>> comparator) {
return () -> Iterators.unmodifiable(Lists.sort(toList(), comparator));
}
/**
* @return the minimal element in this {@code EntrySequence} according to their natural order. The entries in the
* sequence must all implement {@link Comparable} or a {@link ClassCastException} will be thrown at runtime.
*
* @since 1.2
*/
@SuppressWarnings("unchecked")
default Optional> min() {
return min((Comparator) Comparator.naturalOrder());
}
/**
* @return the maximum element in this {@code EntrySequence} according to their natural order. The entries in the
* sequence must all implement {@link Comparable} or a {@link ClassCastException} will be thrown at runtime.
*
* @since 1.2
*/
@SuppressWarnings("unchecked")
default Optional> max() {
return max((Comparator) Comparator.naturalOrder());
}
/**
* @return the minimal element in this {@code EntrySequence} according to the given {@link Comparator}.
*/
default Optional> min(Comparator super Entry> comparator) {
return reduce(BinaryOperator.minBy(comparator));
}
/**
* @return the maximum element in this {@code EntrySequence} according to the given {@link Comparator}.
*/
default Optional> max(Comparator super Entry> comparator) {
return reduce(BinaryOperator.maxBy(comparator));
}
/**
* @return the count of elements in this {@code EntrySequence}.
*
* @since 1.2
*/
default long size() {
return Iterables.count(this);
}
/**
* @return the count of elements in this {@code EntrySequence}.
*
* @deprecated Use {@link #size()} instead.
*/
@Deprecated
default long count() {
return size();
}
/**
* @return this {@code EntrySequence} as a {@link Stream} of entries.
*/
default Stream> stream() {
return StreamSupport.stream(spliterator(), false);
}
/**
* @return true if all elements in this {@code EntrySequence} satisfy the given predicate, false otherwise.
*/
default boolean all(BiPredicate super K, ? super V> biPredicate) {
return Iterables.all(this, Maps.asPredicate(biPredicate));
}
/**
* @return true if no elements in this {@code EntrySequence} satisfy the given predicate, false otherwise.
*/
default boolean none(BiPredicate super K, ? super V> predicate) {
return !any(predicate);
}
/**
* @return true if any element in this {@code EntrySequence} satisfies the given predicate, false otherwise.
*/
default boolean any(BiPredicate super K, ? super V> biPredicate) {
return Iterables.any(this, Maps.asPredicate(biPredicate));
}
/**
* Allow the given {@link Consumer} to see each element in this {@code EntrySequence} as it is traversed.
*/
default EntrySequence peek(BiConsumer action) {
Consumer super Entry> consumer = Maps.asConsumer(action);
return () -> new PeekingIterator<>(iterator(), consumer);
}
/**
* Append the elements of the given {@link Iterator} to the end of this {@code EntrySequence}.
*
* The appended elements will only be available on the first traversal of the resulting {@code Sequence}.
*/
default EntrySequence append(Iterator extends Entry> iterator) {
return append(Iterables.once(iterator));
}
/**
* Append the elements of the given {@link Iterable} to the end of this {@code EntrySequence}.
*/
default EntrySequence append(Iterable extends Entry> that) {
@SuppressWarnings("unchecked")
Iterable> chainingSequence = new ChainingIterable<>(this, that);
return chainingSequence::iterator;
}
/**
* Append the given elements to the end of this {@code EntrySequence}.
*/
@SuppressWarnings("unchecked")
default EntrySequence append(Entry... entries) {
return append(Iterables.of(entries));
}
/**
* Append the given entry to the end of this {@code EntrySequence}.
*/
@SuppressWarnings("unchecked")
default EntrySequence appendEntry(K key, V value) {
return append(Maps.entry(key, value));
}
/**
* Append the elements of the given {@link Stream} to the end of this {@code EntrySequence}.
*
* The appended elements will only be available on the first traversal of the resulting {@code EntrySequence}.
*/
default EntrySequence append(Stream> stream) {
return append(stream.iterator());
}
/**
* Convert this {@code EntrySequence} to a {@link Sequence} of {@link Entry} elements.
*/
default Sequence> toSequence() {
return Sequence.from(this);
}
/**
* Convert this {@code EntrySequence} to a {@link Sequence} where each item is generated by the given mapper.
*/
default Sequence toSequence(BiFunction super K, ? super V, ? extends T> mapper) {
return toSequence(Maps.asFunction(mapper));
}
/**
* Convert this {@code EntrySequence} to a {@link Sequence} where each item is generated by the given mapper.
*/
default Sequence toSequence(Function super Entry, ? extends T> mapper) {
return () -> new MappingIterator<>(iterator(), mapper);
}
/**
* Convert this {@code EntrySequence} to a {@link BiSequence} of {@link Pair} elements.
*/
default BiSequence toBiSequence() {
return BiSequence.from(Sequence.from(this).map(Pair::from));
}
/**
* Convert this {@code EntrySequence} to a {@link CharSeq} using the given mapper function to map each entry to a
* {@code char}.
*
* @see #toSequence(BiFunction)
* @see #toChars(ToCharFunction)
* @see #toInts(ToIntBiFunction)
* @see #toLongs(ToLongBiFunction)
* @see #toDoubles(ToDoubleBiFunction)
* @see #map(BiFunction)
* @see #flatten(BiFunction)
*
* @since 1.1.1
*/
default CharSeq toChars(ToCharBiFunction super K, ? super V> mapper) {
return toChars(e -> mapper.applyAsChar(e.getKey(), e.getValue()));
}
/**
* Convert this {@code EntrySequence} to an {@link IntSequence} using the given mapper function to map each entry
* to an {@code int}.
*
* @see #toSequence(BiFunction)
* @see #toInts(ToIntFunction)
* @see #toChars(ToCharBiFunction)
* @see #toLongs(ToLongBiFunction)
* @see #toDoubles(ToDoubleBiFunction)
* @see #map(BiFunction)
* @see #flatten(BiFunction)
*
* @since 1.1.1
*/
default IntSequence toInts(ToIntBiFunction super K, ? super V> mapper) {
return toInts(e -> mapper.applyAsInt(e.getKey(), e.getValue()));
}
/**
* Convert this {@code EntrySequence} to a {@link LongSequence} using the given mapper function to map each entry
* to a {@code long}.
*
* @see #toSequence(BiFunction)
* @see #toLongs(ToLongFunction)
* @see #toChars(ToCharBiFunction)
* @see #toInts(ToIntBiFunction)
* @see #toDoubles(ToDoubleBiFunction)
* @see #map(BiFunction)
* @see #flatten(BiFunction)
*
* @since 1.1.1
*/
default LongSequence toLongs(ToLongBiFunction super K, ? super V> mapper) {
return toLongs(e -> mapper.applyAsLong(e.getKey(), e.getValue()));
}
/**
* Convert this {@code EntrySequence} to a {@link DoubleSequence} using the given mapper function to map each entry
* to a {@code double}.
*
* @see #toSequence(BiFunction)
* @see #toDoubles(ToDoubleFunction)
* @see #toChars(ToCharBiFunction)
* @see #toInts(ToIntBiFunction)
* @see #toLongs(ToLongBiFunction)
* @see #map(BiFunction)
* @see #flatten(BiFunction)
*
* @since 1.1.1
*/
default DoubleSequence toDoubles(ToDoubleBiFunction super K, ? super V> mapper) {
return toDoubles(e -> mapper.applyAsDouble(e.getKey(), e.getValue()));
}
/**
* Convert this {@code EntrySequence} to a {@link CharSeq} using the given mapper function to map each entry to a
* {@code char}.
*
* @see #toSequence(Function)
* @see #toChars(ToCharBiFunction)
* @see #toInts(ToIntFunction)
* @see #toLongs(ToLongFunction)
* @see #toDoubles(ToDoubleFunction)
* @see #map(Function)
* @see #flatten(Function)
*
* @since 1.1.1
*/
default CharSeq toChars(ToCharFunction super Entry> mapper) {
return () -> CharIterator.from(iterator(), mapper);
}
/**
* Convert this {@code EntrySequence} to an {@link IntSequence} using the given mapper function to map each entry
* to an {@code int}.
*
* @see #toSequence(Function)
* @see #toInts(ToIntBiFunction)
* @see #toChars(ToCharFunction)
* @see #toLongs(ToLongFunction)
* @see #toDoubles(ToDoubleFunction)
* @see #map(Function)
* @see #flatten(Function)
*
* @since 1.1.1
*/
default IntSequence toInts(ToIntFunction super Entry> mapper) {
return () -> IntIterator.from(iterator(), mapper);
}
/**
* Convert this {@code EntrySequence} to a {@link LongSequence} using the given mapper function to map each entry
* to a {@code long}.
*
* @see #toSequence(Function)
* @see #toLongs(ToLongBiFunction)
* @see #toChars(ToCharFunction)
* @see #toInts(ToIntFunction)
* @see #toDoubles(ToDoubleFunction)
* @see #map(Function)
* @see #flatten(Function)
*
* @since 1.1.1
*/
default LongSequence toLongs(ToLongFunction super Entry> mapper) {
return () -> LongIterator.from(iterator(), mapper);
}
/**
* Convert this {@code EntrySequence} to a {@link DoubleSequence} using the given mapper function to map each entry
* to a {@code double}.
*
* @see #toSequence(Function)
* @see #toDoubles(ToDoubleBiFunction)
* @see #toChars(ToCharFunction)
* @see #toInts(ToIntFunction)
* @see #toLongs(ToLongFunction)
* @see #map(Function)
* @see #flatten(Function)
*
* @since 1.1.1
*/
default DoubleSequence toDoubles(ToDoubleFunction super Entry> mapper) {
return () -> DoubleIterator.from(iterator(), mapper);
}
/**
* Repeat this {@code EntrySequence} forever, producing a sequence that never terminates unless the original
* sequence is empty in which case the resulting sequence is also empty.
*/
default EntrySequence repeat() {
return () -> new RepeatingIterator<>(this, -1);
}
/**
* Repeat this {@code EntrySequence} the given number of times.
*/
default EntrySequence repeat(long times) {
return () -> new RepeatingIterator<>(this, times);
}
/**
* @return an {@code EntrySequence} which iterates over this {@code EntrySequence} in reverse order.
*/
default EntrySequence reverse() {
return () -> new ReverseIterator<>(iterator());
}
/**
* @return an {@code EntrySequence} which iterates over this {@code EntrySequence} in random order.
*/
default EntrySequence shuffle() {
return () -> Iterators.unmodifiable(Lists.shuffle(toList()));
}
/**
* @return an {@code EntrySequence} which iterates over this {@code EntrySequence} in random order as determined by
* the given random generator.
*/
default EntrySequence shuffle(Random random) {
return () -> Iterators.unmodifiable(Lists.shuffle(toList(), random));
}
/**
* @return an {@code EntrySequence} which iterates over this {@code EntrySequence} 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 EntrySequence shuffle(Supplier extends Random> randomSupplier) {
return () -> Iterators.unmodifiable(Lists.shuffle(toList(), randomSupplier.get()));
}
/**
* Remove all elements matched by this sequence using {@link Iterator#remove()}.
*
* @since 1.2
*/
default void clear() {
Iterables.removeAll(this);
}
/**
* Remove all elements matched by this sequence using {@link Iterator#remove()}.
*
* @deprecated Use {@link #clear()} instead.
*/
@Deprecated
default void removeAll() {
clear();
}
/**
* @return true if this {@code EntrySequence} is empty, false otherwise.
*
* @since 1.1
*/
default boolean isEmpty() {
return !iterator().hasNext();
}
/**
* @return true if this {@code EntrySequence} contains the given entry, false otherwise.
*
* @since 1.2
*/
default boolean contains(Entry