![JAR search and dependency download from the Maven repository](/logo.png)
org.d2ab.sequence.EntrySequence Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sequence Show documentation
Show all versions of sequence Show documentation
A lightweight alternative to Java 8 sequential Stream
The newest version!
/*
* 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.*;
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.Objects.requireNonNull;
import static java.util.function.BinaryOperator.maxBy;
import static java.util.function.BinaryOperator.minBy;
import static org.d2ab.util.Preconditions.requireAtLeastOne;
import static org.d2ab.util.Preconditions.requireAtLeastZero;
/**
* 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 IterableCollection> {
/**
* 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 Iterables.>empty()::iterator;
}
/**
* 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(Lists.of(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... items) {
requireNonNull(items, "items");
if (items.length % 2 != 0)
throw new IllegalArgumentException("Expected an even number of items: " + items.length);
List> entries = new ArrayList<>();
for (int i = 0; i < items.length; i += 2)
entries.add(Maps.entry((K) items[i], (V) items[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) {
requireNonNull(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)
* @deprecated Use {@link #concat(Iterable[])} instead.
*/
@SafeVarargs
@Deprecated
static EntrySequence from(Iterable>... iterables) {
return concat(iterables);
}
/**
* 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 concat(Iterable>... iterables) {
requireNonNull(iterables, "iterables");
for (Iterable> iterable : iterables)
requireNonNull(iterable, "each iterable");
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) {
requireNonNull(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) {
requireNonNull(stream, "stream");
return once(stream.iterator());
}
/**
* 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) {
requireNonNull(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) {
requireNonNull(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) {
requireNonNull(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) {
requireNonNull(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) {
requireNonNull(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>> multiSupplier) {
requireNonNull(multiSupplier, "multiSupplier");
return () -> {
Supplier extends Entry> supplier = requireNonNull(
multiSupplier.get(), "multiSupplier.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> operator) {
requireNonNull(operator, "operator");
return recurse(Maps.entry(keySeed, valueSeed), entry -> operator.apply(entry.getKey(), entry.getValue()));
}
/**
* 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 seed, UnaryOperator> operator) {
requireNonNull(operator, "operator");
return () -> new RecursiveIterator<>(seed, operator);
}
/**
* 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) {
requireNonNull(f, "f");
requireNonNull(g, "g");
Function, Entry> f1 = asEntryFunction(f);
Function, Entry> g1 = asEntryFunction(g);
return recurse(f.apply(keySeed, valueSeed), f1.compose(g1)::apply);
}
static BinaryOperator> asEntryBinaryOperator(
QuaternaryFunction super K, ? super V, ? super K, ? super V, ? extends Entry> f) {
return (e1, e2) -> f.apply(e1.getKey(), e1.getValue(), e2.getKey(), e2.getValue());
}
static Function, R> asEntryFunction(
BiFunction super K, ? super V, ? extends R> mapper) {
return entry -> mapper.apply(entry.getKey(), entry.getValue());
}
static Predicate> asEntryPredicate(BiPredicate super K, ? super V> predicate) {
return entry -> predicate.test(entry.getKey(), entry.getValue());
}
static Consumer> asEntryConsumer(BiConsumer super K, ? super V> action) {
return entry -> action.accept(entry.getKey(), entry.getValue());
}
/**
* 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) {
requireNonNull(mapper, "mapper");
return map(asEntryFunction(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) {
requireNonNull(mapper, "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) {
requireNonNull(keyMapper, "keyMapper");
requireNonNull(valueMapper, "valueMapper");
return map(entry -> Maps.entry(keyMapper.apply(entry.getKey()), valueMapper.apply(entry.getValue())));
}
/**
* 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(
ObjIntFunction super Entry, ? extends Entry> mapper) {
requireNonNull(mapper, "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(
ObjObjIntFunction super K, ? super V, ? extends Entry> mapper) {
requireNonNull(mapper, "mapper");
return mapIndexed((e, i) -> mapper.apply(e.getKey(), e.getValue(), i));
}
/**
* Map the keys of the entries in this {@code EntrySequence} to another set of keys specified by the given
* {@code mapper} function.
*
* @see #map(Function)
* @see #map(BiFunction)
* @see #map(Function, Function)
* @see #flatten(Function)
*/
default EntrySequence mapKeys(Function super K, ? extends KK> mapper) {
return map((k, v) -> Maps.entry(mapper.apply(k), v));
}
/**
* Map the keys of the entries in this {@code EntrySequence} to another set of keys specified by the given
* {@code mapper} function.
*
* @see #map(Function)
* @see #map(BiFunction)
* @see #map(Function, Function)
* @see #flatten(Function)
*/
default EntrySequence mapValues(Function super V, ? extends VV> mapper) {
return map((k, v) -> Maps.entry(k, mapper.apply(v)));
}
/**
* Skip a set number of steps in this {@code EntrySequence}.
*/
default EntrySequence skip(int skip) {
requireAtLeastZero(skip, "skip");
if (skip == 0)
return this;
return () -> new SkippingIterator<>(iterator(), skip);
}
/**
* Skip a set number of steps at the end of this {@code EntrySequence}.
*
* @since 1.1
*/
default EntrySequence skipTail(int skip) {
requireAtLeastZero(skip, "skip");
if (skip == 0)
return this;
return () -> new TailSkippingIterator<>(iterator(), skip);
}
/**
* Limit the maximum number of results returned by this {@code EntrySequence}.
*/
default EntrySequence limit(int limit) {
requireAtLeastZero(limit, "limit");
if (limit == 0)
return empty();
return () -> new LimitingIterator<>(iterator(), limit);
}
/**
* Limit the results returned by this {@code EntrySequence} to the last {@code limit} entries.
*
* @since 2.3
*/
default EntrySequence limitTail(int limit) {
requireAtLeastZero(limit, "limit");
if (limit == 0)
return empty();
return () -> new TailLimitingIterator<>(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) {
requireNonNull(predicate, "predicate");
return filter(asEntryPredicate(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) {
requireNonNull(predicate, "predicate");
return () -> new FilteringIterator<>(iterator(), predicate);
}
/**
* Filter the entries in this {@code EntrySequence}, keeping only the elements that match the given
* {@link ObjIntPredicate}, which is passed the current entry and its index in the sequence.
*
* @since 1.2
*/
default EntrySequence filterIndexed(ObjIntPredicate super Entry> predicate) {
requireNonNull(predicate, "predicate");
return () -> new IndexedFilteringIterator<>(iterator(), predicate);
}
/**
* Filter the entries in this {@code EntrySequence}, keeping only the elements that match the given
* {@link ObjIntPredicate}, which is passed the current entry and its index in the sequence.
*
* @since 1.2
*/
default EntrySequence filterIndexed(ObjObjIntPredicate super K, ? super V> predicate) {
requireNonNull(predicate, "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) {
requireNonNull(entries, "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) {
requireNonNull(entries, "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) {
requireNonNull(entries, "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.
*/
@SuppressWarnings("unchecked")
default Sequence flatten() {
return toSequence().flatten(entry -> Iterables.fromEntry((Entry) entry));
}
/**
* 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) {
requireNonNull(mapper, "mapper");
return flatten(asEntryFunction(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) {
requireNonNull(mapper, "mapper");
return ChainingIterable.concat(toSequence(mapper))::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) {
requireNonNull(mapper, "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) {
requireNonNull(mapper, "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> predicate) {
requireNonNull(predicate, "predicate");
return until(asEntryPredicate(predicate));
}
/**
* 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> predicate) {
requireNonNull(predicate, "predicate");
return endingAt(asEntryPredicate(predicate));
}
/**
* 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> predicate) {
requireNonNull(predicate, "predicate");
return () -> new ExclusiveTerminalIterator<>(iterator(), predicate);
}
/**
* 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> predicate) {
requireNonNull(predicate, "predicate");
return () -> new InclusiveTerminalIterator<>(iterator(), predicate);
}
/**
* 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) {
requireNonNull(predicate, "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) {
requireNonNull(predicate, "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) {
requireNonNull(predicate, "predicate");
return startingAfter(asEntryPredicate(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) {
requireNonNull(predicate, "predicate");
return startingFrom(asEntryPredicate(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) {
requireNonNull(constructor, "constructor");
List> list = toList();
return list.toArray(constructor.apply(list.size()));
}
/**
* 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) {
requireNonNull(constructor, "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) {
requireNonNull(constructor, "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}. If the same key occurs more than once
* in the {@code EntrySequence}, the key is remapped in the resulting map to the latter corresponding value.
*/
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. If the same key occurs more than once in the {@code EntrySequence}, the key is remapped in the
* resulting map to the latter corresponding value.
*/
default > M toMap(Supplier extends M> constructor) {
requireNonNull(constructor, "constructor");
M result = constructor.get();
for (Entry t : this)
result.put(t.getKey(), t.getValue());
return result;
}
/**
* Collect the entries in this {@code EntrySequence} into a {@link Map}, using the given {@code merger}
* {@link BiFunction} to merge values in the map, according to {@link Map#merge(Object, Object, BiFunction)}.
*/
default Map toMergedMap(BiFunction super V, ? super V, ? extends V> merger) {
return toMergedMap(HashMap::new, merger);
}
/**
* Collect the entries in this {@code EntrySequence} into a {@link Map} of the type determined by the given
* constructor. The given {@code merger} {@link BiFunction} is used to merge values in the map, according to
* {@link Map#merge(Object, Object, BiFunction)}.
*/
default > M toMergedMap(Supplier extends M> constructor,
BiFunction super V, ? super V, ? extends V> merger) {
requireNonNull(constructor, "constructor");
requireNonNull(merger, "merger");
M result = constructor.get();
for (Entry each : this)
result.merge(each.getKey(), each.getValue(), merger);
return result;
}
/**
* Performs a "group by" operation on the entries in this sequence, grouping elements according to their key and
* returning the results in a {@link Map}.
*
* @since 2.3
*/
default Map> toGroupedMap() {
return toGroupedMap(HashMap::new);
}
/**
* Performs a "group by" operation on the entries in this sequence, grouping elements according to their key and
* returning the results in a {@link Map} whose type is determined by the given {@code constructor}.
*
* @since 2.3
*/
default >> M toGroupedMap(Supplier extends M> constructor) {
requireNonNull(constructor, "constructor");
return toGroupedMap(constructor, ArrayList::new);
}
/**
* Performs a "group by" operation on the entries in this sequence, grouping elements according to their key and
* returning the results in a {@link Map} whose type is determined by the given {@code constructor}, using the
* given {@code groupConstructor} to create the target {@link Collection} of the grouped values.
*
* @since 2.3
*/
default , C extends Collection> M toGroupedMap(
Supplier extends M> mapConstructor, Supplier groupConstructor) {
requireNonNull(mapConstructor, "mapConstructor");
requireNonNull(groupConstructor, "groupConstructor");
return toGroupedMap(mapConstructor, Collectors.toCollection(groupConstructor));
}
/**
* Performs a "group by" operation on the entries in this sequence, grouping elements according to their key and
* returning the results in a {@link Map} whose type is determined by the given {@code constructor}, using the
* given group {@link Collector} to collect the grouped values.
*
* @since 2.3
*/
default , C, A> M toGroupedMap(
Supplier extends M> mapConstructor, Collector super V, A, C> groupCollector) {
requireNonNull(mapConstructor, "mapConstructor");
requireNonNull(groupCollector, "groupCollector");
Supplier extends A> groupConstructor = groupCollector.supplier();
BiConsumer super A, ? super V> groupAccumulator = groupCollector.accumulator();
@SuppressWarnings("unchecked")
Map result = (Map) mapConstructor.get();
for (Entry entry : this)
groupAccumulator.accept(result.computeIfAbsent(entry.getKey(), k -> groupConstructor.get()),
entry.getValue());
if (!groupCollector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
@SuppressWarnings("unchecked")
Function super A, ? extends A> groupFinisher = (Function super A, ? extends A>) groupCollector
.finisher();
result.replaceAll((k, v) -> groupFinisher.apply(v));
}
@SuppressWarnings("unchecked")
M castResult = (M) result;
return castResult;
}
/**
* 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) {
requireNonNull(constructor, "constructor");
return collectInto(constructor.get());
}
/**
* 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) {
requireNonNull(constructor, "constructor");
requireNonNull(adder, "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) {
requireNonNull(collector, "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) {
requireNonNull(collection, "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) {
requireNonNull(result, "result");
requireNonNull(adder, "adder");
for (Entry t : this)
adder.accept(result, t);
return result;
}
/**
* @return a {@link List} view of this {@code EntrySequence}, which is updated in real time as the backing store of
* the {@code EntrySequence} changes. The list does not implement {@link RandomAccess} and is best accessed in
* sequence. The list does not support {@link List#add}, only removal through {@link Iterator#remove}.
*
* @since 2.2
*/
default List> asList() {
return Iterables.asList(this);
}
/**
* Join this {@code EntrySequence} into a string separated by the given delimiter.
*/
default String join(String delimiter) {
requireNonNull(delimiter, "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) {
requireNonNull(prefix, "prefix");
requireNonNull(delimiter, "delimiter");
requireNonNull(suffix, "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) {
requireNonNull(operator, "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) {
requireNonNull(operator, "operator");
return reduce(asEntryBinaryOperator(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) {
requireNonNull(operator, "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) {
requireNonNull(operator, "operator");
return reduce(Maps.entry(key, value), asEntryBinaryOperator(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 at(0);
}
/**
* @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());
}
/**
* @return the element at the given index, or an empty {@link Optional} if the {@code EntrySequence} is smaller
* than
* the index.
*/
default Optional> at(int index) {
requireAtLeastZero(index, "index");
return Iterators.get(iterator(), index);
}
/**
* @return the first entry of this {@code EntrySequence} that matches the given predicate, or an empty {@link
* Optional} if there are no matching entries in the {@code EntrySequence}.
*
* @since 1.3
*/
default Optional> first(Predicate super Entry> predicate) {
requireNonNull(predicate, "predicate");
return at(0, predicate);
}
/**
* @return the last entry of this {@code EntrySequence} the matches the given predicate, or an empty {@link
* Optional} if there are no matching entries in the {@code EntrySequence}.
*
* @since 1.3
*/
default Optional> last(Predicate super Entry> predicate) {
requireNonNull(predicate, "predicate");
return filter(predicate).last();
}
/**
* @return the entry at the given index out of the entries matching the given predicate, or an empty {@link
* Optional} if the {@code EntrySequence} of matching entries is smaller than the index.
*
* @since 1.3
*/
default Optional> at(int index, Predicate super Entry> predicate) {
requireAtLeastZero(index, "index");
requireNonNull(predicate, "predicate");
return filter(predicate).at(index);
}
/**
* @return the first entry of this {@code EntrySequence} that matches the given predicate, or an empty {@link
* Optional} if there are no matching entries in the {@code EntrySequence}.
*
* @since 1.3
*/
default Optional> first(BiPredicate super K, ? super V> predicate) {
requireNonNull(predicate, "predicate");
return at(0, predicate);
}
/**
* @return the last entry of this {@code EntrySequence} the matches the given predicate, or an empty {@link
* Optional} if there are no matching entries in the {@code EntrySequence}.
*
* @since 1.3
*/
default Optional> last(BiPredicate super K, ? super V> predicate) {
requireNonNull(predicate, "predicate");
return filter(predicate).last();
}
/**
* @return the entry at the given index out of the entries matching the given predicate, or an empty {@link
* Optional} if the {@code EntrySequence} of matching entries is smaller than the index.
*
* @since 1.3
*/
default Optional> at(int index, BiPredicate super K, ? super V> predicate) {
requireAtLeastZero(index, "index");
requireNonNull(predicate, "predicate");
return filter(predicate).at(index);
}
/**
* Window the elements of this {@code EntrySequence} into a {@link Sequence} of {@code EntrySequence}s of entries,
* 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) {
requireAtLeastOne(window, "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) {
requireAtLeastOne(window, "window");
requireAtLeastOne(step, "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) {
requireAtLeastOne(size, "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) {
requireNonNull(predicate, "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) {
requireNonNull(predicate, "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) {
requireNonNull(predicate, "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) {
requireNonNull(predicate, "predicate");
return split(asEntryPredicate(predicate));
}
/**
* Skip x number of steps in between each invocation of the iterator of this {@code EntrySequence}.
*/
default EntrySequence step(int step) {
requireAtLeastOne(step, "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 of the key and value. Requires that the
* key and value in this sequence implements {@link Comparable} or a {@link ClassCastException} will be thrown.
*
* @throws ClassCastException if the keys and values in this {@code EntrySequence} does not implement {@link
* Comparable}.
*/
default EntrySequence sorted() {
return sorted(Maps.entryComparator());
}
/**
* @return this {@code EntrySequence} sorted according to the given {@link Comparator}.
*/
default EntrySequence sorted(Comparator super Entry extends K, ? extends V>> comparator) {
requireNonNull(comparator, "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) {
requireNonNull(comparator, "comparator");
return reduce(minBy(comparator));
}
/**
* @return the maximum element in this {@code EntrySequence} according to the given {@link Comparator}.
*/
default Optional> max(Comparator super Entry> comparator) {
requireNonNull(comparator, "comparator");
return reduce(maxBy(comparator));
}
/**
* @return true if all elements in this {@code EntrySequence} satisfy the given predicate, false otherwise.
*/
default boolean all(BiPredicate super K, ? super V> predicate) {
requireNonNull(predicate, "predicate");
return Iterables.all(this, asEntryPredicate(predicate));
}
/**
* @return true if no elements in this {@code EntrySequence} satisfy the given predicate, false otherwise.
*/
default boolean none(BiPredicate super K, ? super V> predicate) {
requireNonNull(predicate, "predicate");
return Iterables.none(this, asEntryPredicate(predicate));
}
/**
* @return true if any element in this {@code EntrySequence} satisfies the given predicate, false otherwise.
*/
default boolean any(BiPredicate super K, ? super V> predicate) {
requireNonNull(predicate, "predicate");
return Iterables.any(this, asEntryPredicate(predicate));
}
/**
* Allow the given {@link BiConsumer} to see the components of each entry in this {@code EntrySequence} as it is
* traversed.
*/
default EntrySequence