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

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

There is a newer version: 2.3.0
Show 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.function.QuaternaryFunction;
import org.d2ab.function.QuaternaryPredicate;
import org.d2ab.function.chars.ToCharBiFunction;
import org.d2ab.function.chars.ToCharFunction;
import org.d2ab.iterable.ChainingIterable;
import org.d2ab.iterable.Iterables;
import org.d2ab.iterator.*;
import org.d2ab.iterator.chars.CharIterator;
import org.d2ab.iterator.doubles.DoubleIterator;
import org.d2ab.iterator.ints.IntIterator;
import org.d2ab.iterator.longs.LongIterator;
import org.d2ab.util.Pair;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyIterator;

/**
 * An {@link Iterable} sequence of {@link Pair}s with {@link Stream}-like operations for refining, transforming and
 * collating the list of {@link Pair}s.
 */
@FunctionalInterface
public interface BiSequence extends Iterable> {
	/**
	 * Create an empty {@code BiSequence} with no items.
	 *
	 * @see #of(Pair)
	 * @see #of(Pair...)
	 * @see #ofPair(Object, Object)
	 * @see #ofPairs(Object...)
	 * @see #from(Iterable)
	 */
	static  BiSequence empty() {
		return once(emptyIterator());
	}

	/**
	 * Create a {@code BiSequence} with one {@link Pair}.
	 *
	 * @see #of(Pair...)
	 * @see #ofPair(Object, Object)
	 * @see #ofPairs(Object...)
	 * @see #from(Iterable)
	 */
	static  BiSequence of(Pair item) {
		return from(Collections.singleton(item));
	}

	/**
	 * Create a {@code BiSequence} with the given {@link Pair}s.
	 *
	 * @see #of(Pair)
	 * @see #ofPair(Object, Object)
	 * @see #ofPairs(Object...)
	 * @see #from(Iterable)
	 */
	@SafeVarargs
	static  BiSequence of(Pair... items) {
		return from(asList(items));
	}

	/**
	 * Create a {@code BiSequence} with one {@link Pair} of the given left and right values.
	 *
	 * @see #ofPairs(Object...)
	 * @see #of(Pair)
	 * @see #of(Pair...)
	 * @see #from(Iterable)
	 */
	static  BiSequence ofPair(L left, R right) {
		return of(Pair.of(left, right));
	}

	/**
	 * Create a {@code BiSequence} with {@link Pair}s of the given left and right values given in sequence in the input
	 * array.
	 *
	 * @throws IllegalArgumentException if the array of left and right values is not of even length.
	 * @see #ofPair(Object, Object)
	 * @see #of(Pair)
	 * @see #of(Pair...)
	 * @see #from(Iterable)
	 */
	@SuppressWarnings("unchecked")
	static  BiSequence ofPairs(Object... os) {
		if (os.length % 2 != 0)
			throw new IllegalArgumentException("Expected an even set of objects, but got: " + os.length);

		List> pairs = new ArrayList<>();
		for (int i = 0; i < os.length; i += 2)
			pairs.add(Pair.of((T) os[i], (U) os[i + 1]));
		return from(pairs);
	}

	/**
	 * Create a {@code BiSequence} from an {@link Iterable} of pairs.
	 *
	 * @see #of(Pair)
	 * @see #of(Pair...)
	 * @see #from(Iterable...)
	 * @see #cache(Iterable)
	 */
	static  BiSequence from(Iterable> iterable) {
		return iterable::iterator;
	}

	/**
	 * Create a concatenated {@code BiSequence} from several {@link Iterable}s of pairs which are concatenated together
	 * to form the stream of pairs in the {@code BiSequence}.
	 *
	 * @see #of(Pair)
	 * @see #of(Pair...)
	 * @see #from(Iterable)
	 */
	@SafeVarargs
	static  BiSequence from(Iterable>... iterables) {
		return () -> new ChainingIterator<>(iterables);
	}

	/**
	 * Create a once-only {@code BiSequence} from an {@link Iterator} of pairs. Note that {@code BiSequence}s created
	 * from {@link Iterator}s cannot be passed over more than once. Further attempts will register the
	 * {@code BiSequence} as empty.
	 *
	 * @see #of(Pair)
	 * @see #of(Pair...)
	 * @see #from(Iterable)
	 * @see #cache(Iterator)
	 *
	 * @since 1.1
	 */
	static  BiSequence once(Iterator> iterator) {
		return from(Iterables.once(iterator));
	}

	/**
	 * Create a once-only {@code BiSequence} from a {@link Stream} of pairs. Note that {@code BiSequence}s created from
	 * {@link Stream}s cannot be passed over more than once. Further attempts will register the {@code BiSequence} as
	 * empty.
	 *
	 * @see #of(Pair)
	 * @see #of(Pair...)
	 * @see #from(Iterable)
	 * @see #once(Iterator)
	 * @see #cache(Stream)
	 *
	 * @since 1.1
	 */
	static  BiSequence once(Stream> stream) {
		return once(stream.iterator());
	}

	/**
	 * Create a once-only {@code BiSequence} from an {@link Iterator} of pairs. Note that {@code BiSequence}s created
	 * from {@link Iterator}s cannot be passed over more than once. Further attempts will register the
	 * {@code BiSequence} as empty.
	 *
	 * @see #of(Pair)
	 * @see #of(Pair...)
	 * @see #from(Iterable)
	 * @see #cache(Iterator)
	 *
	 * @deprecated Use {@link #once(Iterator)} instead.
	 */
	@Deprecated
	static  BiSequence from(Iterator> iterator) {
		return once(iterator);
	}

	/**
	 * Create a once-only {@code BiSequence} from a {@link Stream} of pairs. Note that {@code BiSequence}s created from
	 * {@link Stream}s cannot be passed over more than once. Further attempts will register the {@code BiSequence} as
	 * empty.
	 *
	 * @see #of(Pair)
	 * @see #of(Pair...)
	 * @see #from(Iterable)
	 * @see #once(Iterator)
	 * @see #cache(Stream)
	 *
	 * @deprecated Use {@link #once(Stream)} instead.
	 */
	@Deprecated
	static  BiSequence from(Stream> stream) {
		return once(stream);
	}

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

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

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

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

	/**
	 * @return an infinite {@code BiSequence} generated by repeatedly calling the given supplier. The returned
	 * {@code BiSequence} never terminates naturally.
	 *
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #endingAt(Pair)
	 * @see #until(Pair)
	 */
	static  BiSequence generate(Supplier> supplier) {
		return () -> (InfiniteIterator>) supplier::get;
	}

	/**
	 * Returns a {@code BiSequence} produced by recursively applying the given operation to the given seeds, which
	 * form the first element of the sequence, the second being {@code f(leftSeed, rightSeed)}, the third
	 * {@code f(f(leftSeed, rightSeed))} and so on. The returned {@code BiSequence} never terminates naturally.
	 *
	 * @return a {@code BiSequence} produced by recursively applying the given operation to the given seed
	 *
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #generate(Supplier)
	 * @see #endingAt(Pair)
	 * @see #until(Pair)
	 */
	static  BiSequence recurse(L leftSeed, R rightSeed,
	                                       BiFunction> op) {
		return recurse(Pair.of(leftSeed, rightSeed), Pair.asUnaryOperator(op));
	}

	/**
	 * Returns a {@code BiSequence} 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 BiSequence} never terminates naturally.
	 *
	 * @return a {@code BiSequence} produced by recursively applying the given operation to the given seed
	 *
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #generate(Supplier)
	 * @see #endingAt(Pair)
	 * @see #until(Pair)
	 */
	static  BiSequence recurse(Pair seed, UnaryOperator> op) {
		return () -> new RecursiveIterator<>(seed, op);
	}

	/**
	 * Returns a {@code BiSequence} produced by recursively applying the given mapper {@code f} and incrementer
	 * {@code g} operations to the given seeds, the first element being {@code f(leftSeed, rightSeed)}, the second
	 * being {@code f(g(f(leftSeed, rightSeed)))}, the third {@code f(g(f(g(f(leftSeed, rightSeed)))))} and so on.
	 * The returned {@code BiSequence} never terminates naturally.
	 *
	 * @param f a mapper function for producing elements that are to be included in the sequence, the first being
	 *          f(leftSeed, rightSeed)
	 * @param g an incrementer function for producing the next unmapped element to be included in the sequence,
	 *          applied to the first mapped element f(leftSeed, rightSeed) to produce the second unmapped value
	 *
	 * @return a {@code BiSequence} produced by recursively applying the given mapper and incrementer operations to the
	 * given seeds
	 *
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #endingAt(Pair)
	 * @see #until(Pair)
	 */
	static  BiSequence recurse(L leftSeed, R rightSeed,
	                                                 BiFunction> f,
	                                                 BiFunction> g) {
		return recurse(f.apply(leftSeed, rightSeed), Pair.asUnaryOperator(f, g));
	}

	/**
	 * Map the pairs in this {@code BiSequence} to another set of pairs specified by the given {@code mapper}
	 * function.
	 *
	 * @see #map(Function)
	 * @see #map(Function, Function)
	 * @see #flatten(Function)
	 */
	default  BiSequence map(BiFunction> mapper) {
		Function, ? extends Pair> function = Pair.asFunction(mapper);
		return map(function);
	}

	/**
	 * Map the pairs in this {@code BiSequence} to another set of pairs specified by the given {@code mapper}
	 * function.
	 *
	 * @see #map(BiFunction)
	 * @see #map(Function, Function)
	 * @see #flatten(Function)
	 */
	default  BiSequence map(Function, ? extends Pair> mapper) {
		return () -> new MappingIterator<>(iterator(), mapper);
	}

	/**
	 * Map the pairs in this {@code BiSequence} to another set of pairs specified by the given {@code leftMapper}
	 * amd {@code rightMapper} functions.
	 *
	 * @see #map(BiFunction)
	 * @see #map(Function)
	 * @see #flatten(Function)
	 */
	default  BiSequence map(Function leftMapper,
	                                        Function rightMapper) {
		return map(p -> p.map(leftMapper, rightMapper));
	}

	/**
	 * Skip a set number of steps in this {@code BiSequence}.
	 */
	default BiSequence skip(int skip) {
		return () -> new SkippingIterator<>(iterator(), skip);
	}

	/**
	 * Skip a set number of steps at the end of this {@code BiSequence}.
	 *
	 * @since 1.1
	 */
	default BiSequence skipTail(long skip) {
		if (skip == 0)
			return this;

		return () -> new TailSkippingIterator<>(iterator(), (int) skip);
	}

	/**
	 * Limit the maximum number of results returned by this {@code BiSequence}.
	 */
	default BiSequence limit(int limit) {
		return () -> new LimitingIterator<>(iterator(), limit);
	}

	/**
	 * Filter the elements in this {@code BiSequence}, keeping only the elements that match the given
	 * {@link BiPredicate}.
	 */
	default BiSequence filter(BiPredicate predicate) {
		return filter(Pair.asPredicate(predicate));
	}

	/**
	 * Filter the elements in this {@code BiSequence}, keeping only the pairs that match the given
	 * {@link Predicate}.
	 */
	default BiSequence filter(Predicate> predicate) {
		return () -> new FilteringIterator<>(iterator(), predicate);
	}

	/**
	 * Flatten the elements in this {@code BiSequence} according to the given mapper {@link BiFunction}. The resulting
	 * {@code BiSequence} contains the elements that is the result of applying the mapper {@link BiFunction} to each
	 * element, appended together inline as a single {@code BiSequence}.
	 *
	 * @see #flatten(Function)
	 * @see #flattenLeft(Function)
	 * @see #flattenRight(Function)
	 * @see #map(BiFunction)
	 * @see #map(Function)
	 */
	default  BiSequence flatten(
			BiFunction>> mapper) {
		Function, ? extends Iterable>> function = Pair.asFunction(mapper);
		return flatten(function);
	}

	/**
	 * Flatten the elements in this {@code BiSequence} according to the given mapper {@link Function}. The resulting
	 * {@code BiSequence} contains the pairs that is the result of applying the mapper {@link Function} to each
	 * pair, appended together inline as a single {@code BiSequence}.
	 *
	 * @see #flatten(BiFunction)
	 * @see #flattenLeft(Function)
	 * @see #flattenRight(Function)
	 * @see #map(BiFunction)
	 * @see #map(Function)
	 */
	default  BiSequence flatten(
			Function, ? extends Iterable>> function) {
		ChainingIterable> result = new ChainingIterable<>();
		toSequence(function).forEach(result::append);
		return result::iterator;
	}

	/**
	 * Flatten the left side of each pair in this sequence, applying multiples of left values returned by the given
	 * mapper to the same right value of each pair.
	 *
	 * @see #flattenRight(Function)
	 * @see #flatten(Function)
	 * @see #flatten(BiFunction)
	 */
	default  BiSequence flattenLeft(Function, ? extends Iterable> mapper) {
		return () -> new LeftFlatteningPairIterator<>(iterator(), mapper);
	}

	/**
	 * Flatten the right side of each pair in this sequence, applying multiples of right values returned by the given
	 * mapper to the same left value of each pair.
	 *
	 * @see #flattenLeft(Function)
	 * @see #flatten(Function)
	 * @see #flatten(BiFunction)
	 */
	default  BiSequence flattenRight(Function, ? extends Iterable> mapper) {
		return () -> new RightFlatteningPairIterator<>(iterator(), mapper);
	}

	/**
	 * Terminate this {@code BiSequence} just before the given element is encountered, not including the element in the
	 * {@code BiSequence}.
	 *
	 * @see #until(Predicate)
	 * @see #endingAt(Pair)
	 * @see #generate(Supplier)
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #repeat()
	 */
	default BiSequence until(Pair terminal) {
		return () -> new ExclusiveTerminalIterator<>(iterator(), terminal);
	}

	/**
	 * Terminate this {@code BiSequence} when the given element is encountered, including the element as the last
	 * element in the {@code BiSequence}.
	 *
	 * @see #endingAt(Predicate)
	 * @see #until(Pair)
	 * @see #generate(Supplier)
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #repeat()
	 */
	default BiSequence endingAt(Pair terminal) {
		return () -> new InclusiveTerminalIterator<>(iterator(), terminal);
	}

	/**
	 * Terminate this {@code BiSequence} just before the pair with the given left and right components is encountered,
	 * not including the pair in the {@code BiSequence}.
	 *
	 * @see #until(Pair)
	 * @see #until(Predicate)
	 * @see #until(BiPredicate)
	 * @see #endingAt(Pair)
	 * @see #generate(Supplier)
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #repeat()
	 */
	default BiSequence until(L left, R right) {
		return until(Pair.of(left, right));
	}

	/**
	 * Terminate this {@code BiSequence} when the pair with the given left and right components is encountered,
	 * including the element as the last element in the {@code BiSequence}.
	 *
	 * @see #endingAt(Pair)
	 * @see #endingAt(Predicate)
	 * @see #endingAt(BiPredicate)
	 * @see #until(Pair)
	 * @see #generate(Supplier)
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #repeat()
	 */
	default BiSequence endingAt(L left, R right) {
		return endingAt(Pair.of(left, right));
	}

	/**
	 * Terminate this {@code BiSequence} just before the given predicate is satisfied, not including the element that
	 * satisfies the predicate in the {@code BiSequence}.
	 *
	 * @see #until(Predicate)
	 * @see #until(Object, Object)
	 * @see #until(Pair)
	 * @see #endingAt(BiPredicate)
	 * @see #generate(Supplier)
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #repeat()
	 */
	default BiSequence until(BiPredicate terminal) {
		return until(Pair.asPredicate(terminal));
	}

	/**
	 * Terminate this {@code BiSequence} when the given predicate is satisfied, including the element that satisfies
	 * the predicate as the last element in the {@code BiSequence}.
	 *
	 * @see #endingAt(Predicate)
	 * @see #endingAt(Object, Object)
	 * @see #endingAt(Pair)
	 * @see #until(BiPredicate)
	 * @see #generate(Supplier)
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #repeat()
	 */
	default BiSequence endingAt(BiPredicate terminal) {
		return endingAt(Pair.asPredicate(terminal));
	}

	/**
	 * Terminate this {@code BiSequence} just before the given predicate is satisfied, not including the element that
	 * satisfies the predicate in the {@code BiSequence}.
	 *
	 * @see #until(BiPredicate)
	 * @see #until(Pair)
	 * @see #endingAt(Predicate)
	 * @see #generate(Supplier)
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #repeat()
	 */
	default BiSequence until(Predicate> terminal) {
		return () -> new ExclusiveTerminalIterator<>(iterator(), terminal);
	}

	/**
	 * Terminate this {@code BiSequence} when the given predicate is satisfied, including the element that satisfies
	 * the predicate as the last element in the {@code BiSequence}.
	 *
	 * @see #endingAt(BiPredicate)
	 * @see #endingAt(Pair)
	 * @see #until(Predicate)
	 * @see #generate(Supplier)
	 * @see #recurse(Pair, UnaryOperator)
	 * @see #repeat()
	 */
	default BiSequence endingAt(Predicate> terminal) {
		return () -> new InclusiveTerminalIterator<>(iterator(), terminal);
	}

	/**
	 * Begin this {@code BiSequence} just after the given pair is encountered, not including the pair in the
	 * {@code BiSequence}.
	 *
	 * @see #startingAfter(Predicate)
	 * @see #startingAfter(BiPredicate)
	 * @see #startingFrom(Pair)
	 *
	 * @since 1.1
	 */
	default BiSequence startingAfter(Pair  element) {
		return () -> new ExclusiveStartingIterator<>(iterator(), element);
	}

	/**
	 * Begin this {@code BiSequence} when the given pair is encountered, including the pair as the first element
	 * in the {@code BiSequence}.
	 *
	 * @see #startingFrom(Predicate)
	 * @see #startingFrom(BiPredicate)
	 * @see #startingAfter(Pair)
	 *
	 * @since 1.1
	 */
	default BiSequence startingFrom(Pair element) {
		return () -> new InclusiveStartingIterator<>(iterator(), element);
	}

	/**
	 * Begin this {@code BiSequence} just after the given predicate is satisfied, not including the pair that
	 * satisfies the predicate in the {@code BiSequence}.
	 *
	 * @see #startingAfter(BiPredicate)
	 * @see #startingAfter(Pair)
	 * @see #startingFrom(Predicate)
	 *
	 * @since 1.1
	 */
	default BiSequence startingAfter(Predicate> predicate) {
		return () -> new ExclusiveStartingIterator<>(iterator(), predicate);
	}

	/**
	 * Begin this {@code BiSequence} when the given predicate is satisfied, including the pair that satisfies
	 * the predicate as the first element in the {@code BiSequence}.
	 *
	 * @see #startingFrom(BiPredicate)
	 * @see #startingFrom(Pair)
	 * @see #startingAfter(Predicate)
	 *
	 * @since 1.1
	 */
	default BiSequence startingFrom(Predicate> predicate) {
		return () -> new InclusiveStartingIterator<>(iterator(), predicate);
	}

	/**
	 * Begin this {@code BiSequence} just after the given predicate is satisfied, not including the pair that
	 * satisfies the predicate in the {@code BiSequence}.
	 *
	 * @see #startingAfter(Predicate)
	 * @see #startingAfter(Pair)
	 * @see #startingFrom(Predicate)
	 *
	 * @since 1.1
	 */
	default BiSequence startingAfter(BiPredicate predicate) {
		return startingAfter(Pair.asPredicate(predicate));
	}

	/**
	 * Begin this {@code BiSequence} when the given predicate is satisfied, including the pair that satisfies
	 * the predicate as the first element in the {@code BiSequence}.
	 *
	 * @see #startingFrom(Predicate)
	 * @see #startingFrom(Pair)
	 * @see #startingAfter(Predicate)
	 *
	 * @since 1.1
	 */
	default BiSequence startingFrom(BiPredicate predicate) {
		return startingFrom(Pair.asPredicate(predicate));
	}

	/**
	 * Collect the pairs in this {@code BiSequence} into an array.
	 */
	default Pair[] toArray() {
		return toArray(Pair[]::new);
	}

	/**
	 * Collect the pairs in this {@code BiSequence} into an array of the type determined by the given array
	 * constructor.
	 */
	default Pair[] toArray(IntFunction[]> constructor) {
		List> list = toList();
		@SuppressWarnings("unchecked")
		Pair[] array = list.toArray(constructor.apply(list.size()));
		return array;
	}

	/**
	 * Collect the pairs in this {@code BiSequence} into a {@link List}.
	 */
	default List> toList() {
		return toList(ArrayList::new);
	}

	/**
	 * Collect the pairs in this {@code BiSequence} into a {@link List} of the type determined by the given
	 * constructor.
	 */
	default List> toList(Supplier>> constructor) {
		return toCollection(constructor);
	}

	/**
	 * Collect the pairs in this {@code BiSequence} into a {@link Set}.
	 */
	default Set> toSet() {
		return toSet(HashSet::new);
	}

	/**
	 * Collect the pairs in this {@code BiSequence} into a {@link Set} of the type determined by the given
	 * constructor.
	 */
	default >> S toSet(Supplier constructor) {
		return toCollection(constructor);
	}

	/**
	 * Collect the pairs in this {@code BiSequence} into a {@link SortedSet}.
	 */
	default SortedSet> toSortedSet() {
		return toSet(TreeSet::new);
	}

	/**
	 * Collect the pairs in this {@code BiSequence} into a {@link Map}.
	 */
	default Map toMap() {
		return toMap(HashMap::new);
	}

	/**
	 * Collect the pairs in this {@code BiSequence} into a {@link Map} of the type determined by the given
	 * constructor.
	 */
	default > M toMap(Supplier constructor) {
		return collect(constructor, (result, pair) -> pair.put(result));
	}

	/**
	 * Collect the pairs in this {@code BiSequence} into a {@link SortedMap}.
	 */
	default SortedMap toSortedMap() {
		return toMap(TreeMap::new);
	}

	/**
	 * Collect this {@code BiSequence} into a {@link Collection} of the type determined by the given constructor.
	 */
	default >> C toCollection(Supplier constructor) {
		return collect(constructor, Collection::add);
	}

	/**
	 * Collect this {@code BiSequence} into an arbitrary container using the given constructor and adder.
	 */
	default  C collect(Supplier constructor, BiConsumer> adder) {
		return collectInto(constructor.get(), adder);
	}

	/**
	 * Collect this {@code BiSequence} into an arbitrary container using the given {@link Collector}.
	 */
	default  S collect(Collector, C, S> collector) {
		C intermediary = collect(collector.supplier(), collector.accumulator());
		return collector.finisher().apply(intermediary);
	}

	/**
	 * Collect this {@code BiSequence} into the given {@link Collection}.
	 */
	default >> U collectInto(U collection) {
		return collectInto(collection, Collection::add);
	}

	/**
	 * Collect this {@code Sequence} into the given container, using the given adder.
	 */
	default  C collectInto(C result, BiConsumer> adder) {
		forEach(pair -> adder.accept(result, pair));
		return result;
	}

	/**
	 * Join this {@code BiSequence} into a string separated by the given delimiter.
	 */
	default String join(String delimiter) {
		return join("", delimiter, "");
	}

	/**
	 * Join this {@code BiSequence} into a string separated by the given delimiter, with the given prefix and suffix.
	 */
	default String join(String prefix, String delimiter, String suffix) {
		StringBuilder result = new StringBuilder();
		result.append(prefix);
		boolean first = true;
		for (Pair each : this) {
			if (first)
				first = false;
			else
				result.append(delimiter);
			result.append(each);
		}
		result.append(suffix);
		return result.toString();
	}

	/**
	 * Reduce this {@code BiSequence} into a single element by iteratively applying the given binary operator to
	 * the current result and each pair in this sequence.
	 */
	default Optional> reduce(BinaryOperator> operator) {
		return Iterators.reduce(iterator(), operator);
	}

	/**
	 * Reduce this {@code BiSequence} into a single element by iteratively applying the given function to
	 * the current result and each element in this sequence. The function is passed the left and right components of
	 * the result pair, followed by the left and right components of the current pair, respectively.
	 */
	default Optional> reduce(QuaternaryFunction> operator) {
		return reduce(Pair.asBinaryOperator(operator));
	}

	/**
	 * Reduce this {@code BiSequence} into a single element by iteratively applying the given binary operator to
	 * the current result and each pair in this sequence, starting with the given identity as the initial result.
	 */
	default Pair reduce(Pair identity, BinaryOperator> operator) {
		return Iterators.reduce(iterator(), identity, operator);
	}

	/**
	 * Reduce this {@code BiSequence} 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 left and right components of the result, followed by the left and right components of
	 * the current entry, respectively.
	 */
	default Pair reduce(L left, R right, QuaternaryFunction> operator) {
		return reduce(Pair.of(left, right), Pair.asBinaryOperator(operator));
	}

	/**
	 * @return the first pair of this {@code BiSequence} or an empty {@link Optional} if there are no pairs in the
	 * {@code BiSequence}.
	 */
	default Optional> first() {
		return get(0);
	}

	/**
	 * @return the second pair of this {@code BiSequence} or an empty {@link Optional} if there are one or less pairs
	 * in the {@code BiSequence}.
	 */
	default Optional> second() {
		return get(1);
	}

	/**
	 * @return the third pair of this {@code BiSequence} or an empty {@link Optional} if there are two or less pairs
	 * in the {@code BiSequence}.
	 */
	default Optional> third() {
		return get(2);
	}

	/**
	 * @return the element at the given index, or an empty {@link Optional} if the {@code BiSequence} is smaller
	 * than the index.
	 */
	default Optional> get(long index) {
		return Iterators.get(iterator(), index);
	}

	/**
	 * @return the last pair of this {@code BiSequence} or an empty {@link Optional} if there are no pairs in the
	 * {@code BiSequence}.
	 */
	default Optional> last() {
		Iterator> iterator = iterator();
		if (!iterator.hasNext())
			return Optional.empty();

		Pair last;
		do {
			last = iterator.next();
		} while (iterator.hasNext());

		return Optional.of(last);
	}

	/**
	 * Window the elements of this {@code BiSequence} into a {@link Sequence} of {@code BiSequence}s of pairs, each
	 * with the size of the given window. The first item in each sequence is the second item in the previous sequence.
	 * The final sequence may be shorter than the window. This method is equivalent to {@code window(window, 1)}.
	 */
	default Sequence> window(int window) {
		return window(window, 1);
	}

	/**
	 * Window the elements of this {@code BiSequence} into a sequence of {@code BiSequence}s of elements, each with the
	 * size of the given window, stepping {@code step} elements between each window. If the given step is less than the
	 * window size, the windows will overlap each other. If the step is larger than the window size, elements will be
	 * skipped in between windows.
	 */
	default Sequence> window(int window, int step) {
		return () -> new WindowingIterator, BiSequence>(iterator(), window, step) {
			@Override
			protected BiSequence toSequence(List> list) {
				return BiSequence.from(list);
			}
		};
	}

	/**
	 * Batch the elements of this {@code BiSequence} into a sequence of {@code BiSequence}s of distinct elements, each
	 * with the given batch size. This method is equivalent to {@code window(size, size)}.
	 */
	default Sequence> batch(int size) {
		return window(size, size);
	}

	/**
	 * Batch the elements of this {@code BiSequence} into a sequence of {@link BiSequence}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 Pair> predicate) {
		return () -> new PredicatePartitioningIterator, BiSequence>(iterator(), predicate) {
			@Override
			protected BiSequence toSequence(List> list) {
				return BiSequence.from(list);
			}
		};
	}

	/**
	 * Batch the elements of this {@code BiSequence} into a sequence of {@link BiSequence}s of distinct elements,
	 * where the given predicate determines where to split the lists of partitioned elements. The predicate is given
	 * the left and right 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) {
		return batch((p1, p2) -> predicate.test(p1.getLeft(), p1.getRight(), p2.getLeft(), p2.getRight()));
	}

	/**
	 * Split the elements of this {@code BiSequence} into a sequence of {@code BiSequence}s of distinct elements,
	 * around the given element. The elements around which the sequence is split are not included in the result.
	 *
	 * @since 1.1
	 */
	default Sequence> split(Pair element) {
		return () -> new SplittingIterator, BiSequence>(iterator(), element) {
			@Override
			protected BiSequence toSequence(List> list) {
				return BiSequence.from(list);
			}
		};
	}

	/**
	 * Split the elements of this {@code BiSequence} into a sequence of {@code BiSequence}s of distinct elements,
	 * where the given predicate determines which elements to split the partitioned elements around. The elements
	 * matching the predicate are not included in the result.
	 *
	 * @since 1.1
	 */
	default Sequence> split(Predicate> predicate) {
		return () -> new SplittingIterator, BiSequence>(iterator(), predicate) {
			@Override
			protected BiSequence toSequence(List> list) {
				return BiSequence.from(list);
			}
		};
	}

	/**
	 * Split the elements of this {@code BiSequence} into a sequence of {@code BiSequence}s of distinct elements,
	 * where the given predicate determines which elements to split the partitioned elements around. The elements
	 * matching the predicate are not included in the result.
	 *
	 * @since 1.1
	 */
	default Sequence> split(BiPredicate predicate) {
		return split(Pair.asPredicate(predicate));
	}

	/**
	 * Skip x number of steps in between each invocation of the iterator of this {@code BiSequence}.
	 */
	default BiSequence step(int step) {
		return () -> new SteppingIterator<>(iterator(), step);
	}

	/**
	 * @return a {@code BiSequence} where each item in this {@code BiSequence} occurs only once, the first time it is
	 * encountered.
	 */
	default BiSequence distinct() {
		return () -> new DistinctIterator<>(iterator());
	}

	/**
	 * @return this {@code BiSequence} sorted according to the natural order.
	 */
	default BiSequence sorted() {
		return () -> new SortingIterator<>(iterator());
	}

	/**
	 * @return this {@code BiSequence} sorted according to the given {@link Comparator}.
	 */
	default BiSequence sorted(Comparator> comparator) {
		return () -> new SortingIterator<>(iterator(), comparator);
	}

	/**
	 * @return the minimal element in this {@code BiSequence} according to the given {@link Comparator}.
	 */
	default Optional> min(Comparator> comparator) {
		return reduce(BinaryOperator.minBy(comparator));
	}

	/**
	 * @return the maximum element in this {@code BiSequence} according to the given {@link Comparator}.
	 */
	default Optional> max(Comparator> comparator) {
		return reduce(BinaryOperator.maxBy(comparator));
	}

	/**
	 * @return the count of elements in this {@code BiSequence}.
	 */
	default int count() {
		int count = 0;
		for (Pair ignored : this)
			count++;
		return count;
	}

	/**
	 * @return this {@code BiSequence} as a {@link Stream} of pairs.
	 */
	default Stream> stream() {
		return StreamSupport.stream(spliterator(), false);
	}

	/**
	 * @return true if all elements in this {@code BiSequence} satisfy the given predicate, false otherwise.
	 */
	default boolean all(BiPredicate biPredicate) {
		return Iterables.all(this, Pair.asPredicate(biPredicate));
	}

	/**
	 * @return true if no elements in this {@code BiSequence} satisfy the given predicate, false otherwise.
	 */
	default boolean none(BiPredicate predicate) {
		return !any(predicate);
	}

	/**
	 * @return true if any element in this {@code BiSequence} satisfies the given predicate, false otherwise.
	 */
	default boolean any(BiPredicate biPredicate) {
		return Iterables.any(this, Pair.asPredicate(biPredicate));
	}

	/**
	 * Allow the given {@link Consumer} to see each element in this {@code BiSequence} as it is traversed.
	 */
	default BiSequence peek(BiConsumer action) {
		Consumer> consumer = Pair.asConsumer(action);
		return () -> new PeekingIterator<>(iterator(), consumer);
	}

	/**
	 * Append the elements of the given {@link Iterator} to the end of this {@code BiSequence}.
	 * 

* The appended elements will only be available on the first traversal of the resulting {@code Sequence}. */ default BiSequence append(Iterator> iterator) { return append(Iterables.once(iterator)); } /** * Append the elements of the given {@link Iterable} to the end of this {@code BiSequence}. */ default BiSequence append(Iterable> that) { @SuppressWarnings("unchecked") Iterable> chainingSequence = new ChainingIterable<>(this, that); return chainingSequence::iterator; } /** * Append the given elements to the end of this {@code BiSequence}. */ @SuppressWarnings("unchecked") default BiSequence append(Pair... entries) { return append(Iterables.of(entries)); } /** * Append the given pair to the end of this {@code BiSequence}. */ @SuppressWarnings("unchecked") default BiSequence appendPair(L left, R right) { return append(Pair.of(left, right)); } /** * Append the elements of the given {@link Stream} to the end of this {@code BiSequence}. *

* The appended elements will only be available on the first traversal of the resulting {@code BiSequence}. */ default BiSequence append(Stream> stream) { return append(stream.iterator()); } /** * Convert this {@code BiSequence} to a {@link Sequence} of {@link Pair}s. */ default Sequence> toSequence() { return Sequence.from(this); } /** * Convert this {@code BiSequence} to a {@link Sequence} where each item is generated by the given mapper. */ default Sequence toSequence(BiFunction mapper) { Function, ? extends T> function = Pair.asFunction(mapper); return toSequence(function); } /** * Convert this {@code BiSequence} to a {@link Sequence} where each item is generated by the given mapper. */ default Sequence toSequence(Function, ? extends T> mapper) { return () -> new MappingIterator<>(iterator(), mapper); } /** * Convert this {@code BiSequence} to a {@link CharSeq} using the given mapper function to map each pair 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) */ default CharSeq toChars(ToCharBiFunction mapper) { return toChars(p -> mapper.applyAsChar(p.getLeft(), p.getRight())); } /** * Convert this {@code BiSequence} to an {@link IntSequence} using the given mapper function to map each pair * 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) */ default IntSequence toInts(ToIntBiFunction mapper) { return toInts(p -> mapper.applyAsInt(p.getLeft(), p.getRight())); } /** * Convert this {@code BiSequence} to a {@link LongSequence} using the given mapper function to map each pair 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) */ default LongSequence toLongs(ToLongBiFunction mapper) { return toLongs(p -> mapper.applyAsLong(p.getLeft(), p.getRight())); } /** * Convert this {@code BiSequence} to a {@link DoubleSequence} using the given mapper function to map each pair * 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) */ default DoubleSequence toDoubles(ToDoubleBiFunction mapper) { return toDoubles(p -> mapper.applyAsDouble(p.getLeft(), p.getRight())); } /** * Convert this {@code BiSequence} to a {@link CharSeq} using the given mapper function to map each pair 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) */ default CharSeq toChars(ToCharFunction> mapper) { return () -> CharIterator.from(iterator(), mapper); } /** * Convert this {@code BiSequence} to an {@link IntSequence} using the given mapper function to map each pair * 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) */ default IntSequence toInts(ToIntFunction> mapper) { return () -> IntIterator.from(iterator(), mapper); } /** * Convert this {@code BiSequence} to a {@link LongSequence} using the given mapper function to map each pair 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) */ default LongSequence toLongs(ToLongFunction> mapper) { return () -> LongIterator.from(iterator(), mapper); } /** * Convert this {@code BiSequence} to a {@link DoubleSequence} using the given mapper function to map each pair * 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) */ default DoubleSequence toDoubles(ToDoubleFunction> mapper) { return () -> DoubleIterator.from(iterator(), mapper); } /** * Repeat this {@code BiSequence} forever, producing a sequence that never terminates unless the original sequence * is empty in which case the resulting sequence is also empty. */ default BiSequence repeat() { return () -> new RepeatingIterator<>(this, -1); } /** * Repeat this {@code BiSequence} the given number of times. */ default BiSequence repeat(long times) { return () -> new RepeatingIterator<>(this, times); } /** * @return a {@code BiSequence} which iterates over this {@code BiSequence} in reverse order. */ default BiSequence reverse() { return () -> new ReverseIterator<>(iterator()); } /** * @return a {@code BiSequence} which iterates over this {@code BiSequence} in random order. */ default BiSequence shuffle() { return () -> { List> list = toList(); Collections.shuffle(list); return list.iterator(); }; } /** * @return a {@code BiSequence} which iterates over this {@code BiSequence} in random order as determined by the * given random generator. */ default BiSequence shuffle(Random md) { return () -> { List> list = toList(); Collections.shuffle(list, md); return list.iterator(); }; } /** * Remove all elements matched by this sequence using {@link Iterator#remove()}. */ default void removeAll() { Iterables.removeAll(this); } /** * @return true if this {@code BiSequence} is empty, false otherwise. * * @since 1.1 */ default boolean isEmpty() { return !iterator().hasNext(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy