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

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

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>> multiSupplier) {
		requireNonNull(multiSupplier, "multiSupplier");

		return () -> {
			Supplier> 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> f,
	                                                    BiFunction> 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> f) {
		return (e1, e2) -> f.apply(e1.getKey(), e1.getValue(), e2.getKey(), e2.getValue());
	}

	static  Function, R> asEntryFunction(
			BiFunction mapper) {
		return entry -> mapper.apply(entry.getKey(), entry.getValue());
	}

	static  Predicate> asEntryPredicate(BiPredicate predicate) {
		return entry -> predicate.test(entry.getKey(), entry.getValue());
	}

	static  Consumer> asEntryConsumer(BiConsumer 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> 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, ? 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 keyMapper,
	                                           Function 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, ? 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> 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 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 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 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> 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> 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 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> 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> 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>> 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, ? 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, ? 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, ? 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 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 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> 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> 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> 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> 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 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 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 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 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 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 constructor,
	                                            BiFunction 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 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 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 mapConstructor, Collector groupCollector) {
		requireNonNull(mapConstructor, "mapConstructor");
		requireNonNull(groupCollector, "groupCollector");

		Supplier groupConstructor = groupCollector.supplier();
		BiConsumer 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 groupFinisher = (Function) 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 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 constructor, BiConsumer> 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> 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> 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> 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> 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 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 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 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> 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 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> 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 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> 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> 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> 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 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 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 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 peek(BiConsumer action) {
		requireNonNull(action, "action");

		return peek(asEntryConsumer(action));
	}

	/**
	 * Allow the given {@link Consumer} to see each entry in this {@code EntrySequence} as it is traversed.
	 *
	 * @since 1.2.2
	 */
	default EntrySequence peek(Consumer> action) {
		requireNonNull(action, "action");

		return () -> new PeekingIterator<>(iterator(), action);
	}

	/**
	 * Allow the given {@link ObjObjIntConsumer} to see the components of each entry with their index as this
	 * {@code EntrySequence} is traversed.
	 *
	 * @since 1.2.2
	 */
	default EntrySequence peekIndexed(ObjObjIntConsumer action) {
		requireNonNull(action, "action");

		return peekIndexed((p, x) -> action.accept(p.getKey(), p.getValue(), x));
	}

	/**
	 * Allow the given {@link ObjIntConsumer} to see each entry with its index as this {@code EntrySequence} is
	 * traversed.
	 *
	 * @since 1.2.2
	 */
	default EntrySequence peekIndexed(ObjIntConsumer> action) {
		requireNonNull(action, "action");

		return () -> new IndexPeekingIterator<>(iterator(), action);
	}

	/**
	 * 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> iterator) { requireNonNull(iterator, "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> iterable) { requireNonNull(iterable, "iterable"); return ChainingIterable.concat(this, iterable)::iterator; } /** * Append the given elements to the end of this {@code EntrySequence}. */ @SuppressWarnings("unchecked") default EntrySequence append(Entry... entries) { requireNonNull(entries, "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) { requireNonNull(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 mapper) { requireNonNull(mapper, "mapper"); return toSequence(asEntryFunction(mapper)); } /** * Convert this {@code EntrySequence} to a {@link Sequence} where each item is generated by the given mapper. */ default Sequence toSequence(Function, ? extends T> mapper) { requireNonNull(mapper, "mapper"); return () -> new MappingIterator<>(iterator(), mapper); } /** * Convert this {@code EntrySequence} to a {@link BiSequence} of {@link Pair} elements. */ default BiSequence toBiSequence() { return BiSequence.from(toSequence(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 mapper) { requireNonNull(mapper, "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 mapper) { requireNonNull(mapper, "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 mapper) { requireNonNull(mapper, "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 mapper) { requireNonNull(mapper, "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> mapper) { requireNonNull(mapper, "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> mapper) { requireNonNull(mapper, "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> mapper) { requireNonNull(mapper, "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> mapper) { requireNonNull(mapper, "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(int times) { requireAtLeastZero(times, "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) { requireNonNull(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 randomSupplier) { requireNonNull(randomSupplier, "randomSupplier"); return () -> { Random random = requireNonNull(randomSupplier.get(), "randomSupplier.get()"); return Iterators.unmodifiable(Lists.shuffle(toList(), random)); }; } /** * @return true if this {@code EntrySequence} contains the given entry, false otherwise. * * @since 1.2 */ default boolean contains(Entry entry) { return Iterables.contains(this, entry); } /** * @return true if this {@code EntrySequence} contains the given entry, false otherwise. * * @since 1.2 */ default boolean contains(K key, V value) { for (Entry each : this) if (Objects.equals(key, each.getKey()) && Objects.equals(value, each.getValue())) return true; return false; } /** * Perform the given action for each element in this {@code EntrySequence}. * * @since 1.2 */ default void forEach(BiConsumer action) { requireNonNull(action, "action"); forEach(asEntryConsumer(action)); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy