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

javaslang.collection.Traversable Maven / Gradle / Ivy

/*     / \____  _    _  ____   ______  / \ ____  __    _ _____
 *    /  /    \/ \  / \/    \ /  /\__\/  //    \/  \  / /  _  \   Javaslang
 *  _/  /  /\  \  \/  /  /\  \\__\\  \  //  /\  \ /\\/  \__/  /   Copyright 2014-now Daniel Dietrich
 * /___/\_/  \_/\____/\_/  \_/\__\/__/___\_/  \_//  \__/_____/    Licensed under the Apache License, Version 2.0
 */
package javaslang.collection;

import javaslang.Tuple2;
import javaslang.Tuple3;
import javaslang.Value;
import javaslang.control.Match;
import javaslang.control.Option;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * An interface for inherently recursive, multi-valued data structures. The order of elements is determined by
 * {@link Iterable#iterator()}, which may vary each time it is called.
 * 

* Implementations of {@code Traversable} should calculate the {@code hashCode} via {@link #hash(Iterable)}. * *

* Basic operations: * *

    *
  • {@link #clear()}
  • *
  • {@link #contains(Object)}
  • *
  • {@link #containsAll(Iterable)}
  • *
  • {@link #head()}
  • *
  • {@link #headOption()}
  • *
  • {@link #init()}
  • *
  • {@link #initOption()}
  • *
  • {@link #isEmpty()}
  • *
  • {@link #last()}
  • *
  • {@link #lastOption()}
  • *
  • {@link #length()}
  • *
  • {@link #size()}
  • *
  • {@link #tail()}
  • *
  • {@link #tailOption()}
  • *
* * Iteration: * *
    *
  • {@link #grouped(long)}
  • *
  • {@link #iterator()}
  • *
  • {@link #sliding(long)}
  • *
  • {@link #sliding(long, long)}
  • *
* * Numeric operations: * *
    *
  • {@link #average()}
  • *
  • {@link #max()}
  • *
  • {@link #maxBy(Comparator)}
  • *
  • {@link #maxBy(Function)}
  • *
  • {@link #min()}
  • *
  • {@link #minBy(Comparator)}
  • *
  • {@link #minBy(Function)}
  • *
  • {@link #product()}
  • *
  • {@link #sum()}
  • *
* * Reduction/Folding: * *
    *
  • {@link #count(Predicate)}
  • *
  • {@link #fold(Object, BiFunction)}
  • *
  • {@link #foldLeft(Object, BiFunction)}
  • *
  • {@link #foldRight(Object, BiFunction)}
  • *
  • {@link #mkString()}
  • *
  • {@link #mkString(CharSequence)}
  • *
  • {@link #mkString(CharSequence, CharSequence, CharSequence)}
  • *
  • {@link #reduce(BiFunction)}
  • *
  • {@link #reduceOption(BiFunction)}
  • *
  • {@link #reduceLeft(BiFunction)}
  • *
  • {@link #reduceLeftOption(BiFunction)}
  • *
  • {@link #reduceRight(BiFunction)}
  • *
  • {@link #reduceRightOption(BiFunction)}
  • *
* * Selection: * *
    *
  • {@link #drop(long)}
  • *
  • {@link #dropRight(long)}
  • *
  • {@link #dropUntil(Predicate)}
  • *
  • {@link #dropWhile(Predicate)}
  • *
  • {@link #filter(Predicate)}
  • *
  • {@link #find(Predicate)}
  • *
  • {@link #findLast(Predicate)}
  • *
  • {@link #groupBy(Function)}
  • *
  • {@link #partition(Predicate)}
  • *
  • {@link #retainAll(Iterable)}
  • *
  • {@link #take(long)}
  • *
  • {@link #takeRight(long)}
  • *
  • {@link #takeUntil(Predicate)}
  • *
  • {@link #takeWhile(Predicate)}
  • *
* * Tests: * *
    *
  • {@link #existsUnique(Predicate)}
  • *
  • {@link #hasDefiniteSize()}
  • *
  • {@link #isTraversableAgain()}
  • *
* * Transformation: * *
    *
  • {@link #distinct()}
  • *
  • {@link #distinctBy(Comparator)}
  • *
  • {@link #distinctBy(Function)}
  • *
  • {@link #flatMap(Function)}
  • *
  • {@link #map(Function)}
  • *
  • {@link #replace(Object, Object)}
  • *
  • {@link #replaceAll(Object, Object)}
  • *
  • {@link #scan(Object, BiFunction)}
  • *
  • {@link #scanLeft(Object, BiFunction)}
  • *
  • {@link #scanRight(Object, BiFunction)}
  • *
  • {@link #span(Predicate)}
  • *
  • {@link #unzip(Function)}
  • *
  • {@link #unzip3(Function)}
  • *
  • {@link #zip(Iterable)}
  • *
  • {@link #zipAll(Iterable, Object, Object)}
  • *
  • {@link #zipWithIndex()}
  • *
* * @param Component type * @author Daniel Dietrich and others * @since 1.1.0 */ public interface Traversable extends Foldable, Value { /** * Used by collections to compute the hashCode only once. *

* Idiom: *

     * 
     * class MyCollection implements Serializable {
     *
     *     // Not allowed to be serialized!
     *     private final transient Lazy<Integer> hashCode = Lazy.of(() -> Traversable.hash(this));
     *
     *     @Override
     *     public int hashCode() {
     *         return hashCode.get();
     *     }
     * }
     * 
     * 
* * Note: In the case of an empty collection, such as {@code Nil} it is recommended to * directly return {@code Traversable.hash(this)} instead of asking a {@code Lazy} value: *
     * 
     * interface List<T> {
     *
     *     class Nil<T> {
     *
     *         @Override
     *         public int hashCode() {
     *             return Traversable.hash(this);
     *         }
     *     }
     * }
     * 
     * 
* * @param Component type * @param objects An Iterable * @return The hashCode of the given Iterable * @throws NullPointerException if objects is null */ static int hash(Iterable objects) { int hashCode = 1; for (Object o : objects) { hashCode = 31 * hashCode + Objects.hashCode(o); } return hashCode; } /** * Narrows a widened {@code Traversable} to {@code Traversable} * by performing a type safe-cast. This is eligible because immutable/read-only * collections are covariant. * * @param traversable An {@code Traversable}. * @param Component type of the {@code Traversable}. * @return the given {@code traversable} instance as narrowed type {@code Traversable}. */ @SuppressWarnings("unchecked") static Traversable narrow(Traversable traversable) { return (Traversable) traversable; } /** * Calculates the average of this elements. Returns {@code None} if this is empty, otherwise {@code Some(average)}. * Supported component types are {@code Byte}, {@code Double}, {@code Float}, {@code Integer}, {@code Long}, * {@code Short}, {@code BigInteger} and {@code BigDecimal}. *

* Examples: *

     * 
     * List.empty().average()              // = None
     * List.of(1, 2, 3).average()          // = Some(2.0)
     * List.of(0.1, 0.2, 0.3).average()    // = Some(0.2)
     * List.of("apple", "pear").average()  // throws
     * 
     * 
* * @return {@code Some(average)} or {@code None}, if there are no elements * @throws UnsupportedOperationException if this elements are not numeric */ @SuppressWarnings("unchecked") default Option average() { if (isEmpty()) { return Option.none(); } else { final Traversable objects = isTraversableAgain() ? this : toStream(); final Object head = objects.head(); final double d; if (head instanceof Integer || head instanceof Short || head instanceof Byte) { d = ((Traversable) objects) .toJavaStream() .mapToInt(Number::intValue) .average() .getAsDouble(); } else if (head instanceof Double || head instanceof Float || head instanceof BigDecimal) { d = ((Traversable) objects) .toJavaStream() .mapToDouble(Number::doubleValue) .average() .getAsDouble(); } else if (head instanceof Long || head instanceof BigInteger) { d = ((Traversable) objects) .toJavaStream() .mapToLong(Number::longValue) .average() .getAsDouble(); } else { throw new UnsupportedOperationException("not numeric"); } return Option.some(d); } } /** * Returns an empty version of this traversable, i.e. {@code this.clear().isEmpty() == true}. * * @return an empty Traversable. */ Traversable clear(); /** * Tests if this Traversable contains all given elements. *

* The result is equivalent to * {@code elements.isEmpty() ? true : contains(elements.head()) && containsAll(elements.tail())} but implemented * without recursion. * * @param elements A List of values of type T. * @return true, if this List contains all given elements, false otherwise. * @throws NullPointerException if {@code elements} is null */ default boolean containsAll(Iterable elements) { Objects.requireNonNull(elements, "elements is null"); return List.ofAll(elements).distinct().find(e -> !this.contains(e)).isEmpty(); } /** * Counts the elements which satisfy the given predicate. * * @param predicate A predicate * @return A number {@code >= 0} * @throws NullPointerException if {@code predicate} is null. */ default int count(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); return foldLeft(0, (i, t) -> predicate.test(t) ? i + 1 : i); } /** * Returns a new version of this which contains no duplicates. Elements are compared using {@code equals}. * * @return a new {@code Traversable} containing this elements without duplicates */ Traversable distinct(); /** * Returns a new version of this which contains no duplicates. Elements are compared using the given * {@code comparator}. * * @param comparator A comparator * @return a new {@code Traversable} containing this elements without duplicates * @throws NullPointerException if {@code comparator} is null. */ Traversable distinctBy(Comparator comparator); /** * Returns a new version of this which contains no duplicates. Elements mapped to keys which are compared using * {@code equals}. *

* The elements of the result are determined in the order of their occurrence - first match wins. * * @param keyExtractor A key extractor * @param key type * @return a new {@code Traversable} containing this elements without duplicates * @throws NullPointerException if {@code keyExtractor} is null */ Traversable distinctBy(Function keyExtractor); /** * Drops the first n elements of this or all elements, if this length < n. * * @param n The number of elements to drop. * @return a new instance consisting of all elements of this except the first n ones, or else the empty instance, * if this has less than n elements. */ Traversable drop(long n); /** * Drops the last n elements of this or all elements, if this length < n. * * @param n The number of elements to drop. * @return a new instance consisting of all elements of this except the last n ones, or else the empty instance, * if this has less than n elements. */ Traversable dropRight(long n); /** * Drops elements until the predicate holds for the current element. *

* Note: This is essentially the same as {@code dropWhile(predicate.negate())}. It is intended to be used with * method references, which cannot be negated directly. * * @param predicate A condition tested subsequently for this elements. * @return a new instance consisting of all elements starting from the first one which does satisfy the given * predicate. * @throws NullPointerException if {@code predicate} is null */ Traversable dropUntil(Predicate predicate); /** * Drops elements while the predicate holds for the current element. * * @param predicate A condition tested subsequently for this elements starting with the first. * @return a new instance consisting of all elements starting from the first one which does not satisfy the * given predicate. * @throws NullPointerException if {@code predicate} is null */ Traversable dropWhile(Predicate predicate); /** * Checks, if a unique elements exists such that the predicate holds. * * @param predicate A Predicate * @return true, if predicate holds for a unique element, false otherwise * @throws NullPointerException if {@code predicate} is null */ default boolean existsUnique(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); boolean exists = false; for (T t : this) { if (predicate.test(t)) { if (exists) { return false; } else { exists = true; } } } return exists; } /** * Returns a new traversable consisting of all elements which satisfy the given predicate. * * @param predicate A predicate * @return a new traversable * @throws NullPointerException if {@code predicate} is null */ Traversable filter(Predicate predicate); /** * Returns the first element of this which satisfies the given predicate. * * @param predicate A predicate. * @return Some(element) or None, where element may be null (i.e. {@code List.of(null).find(e -> e == null)}). * @throws NullPointerException if {@code predicate} is null */ default Option find(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); for (T a : this) { if (predicate.test(a)) { return Option.some(a); // may be Some(null) } } return Option.none(); } /** * Returns the last element of this which satisfies the given predicate. *

* Same as {@code reverse().find(predicate)}. * * @param predicate A predicate. * @return Some(element) or None, where element may be null (i.e. {@code List.of(null).find(e -> e == null)}). * @throws NullPointerException if {@code predicate} is null */ default Option findLast(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); return iterator().findLast(predicate); } /** * FlatMaps this Traversable. * * @param mapper A mapper * @param The resulting component type. * @return A new Traversable instance. */ Traversable flatMap(Function> mapper); /** * Accumulates the elements of this Traversable by successively calling the given function {@code f} from the left, * starting with a value {@code zero} of type B. *

* Example: Reverse and map a Traversable in one pass *


     * List.of("a", "b", "c").foldLeft(List.empty(), (xs, x) -> xs.prepend(x.toUpperCase()))
     * // = List("C", "B", "A")
     * 
* * @param zero Value to start the accumulation with. * @param f The accumulator function. * @param Result type of the accumulator. * @return an accumulated version of this. * @throws NullPointerException if {@code f} is null */ @Override default U foldLeft(U zero, BiFunction f) { Objects.requireNonNull(f, "f is null"); U xs = zero; for (T x : this) { xs = f.apply(xs, x); } return xs; } /** * Accumulates the elements of this Traversable by successively calling the given function {@code f} from the right, * starting with a value {@code zero} of type B. *

* Example: {@code List.of("a", "b", "c").foldRight("", (x, xs) -> x + xs) = "abc"} * * @param zero Value to start the accumulation with. * @param f The accumulator function. * @param Result type of the accumulator. * @return an accumulated version of this. * @throws NullPointerException if {@code f} is null */ @Override U foldRight(U zero, BiFunction f); @Override default T get() { return iterator().next(); } /** * Groups this elements by classifying the elements. * * @param classifier A function which classifies elements into classes * @param classified class type * @return A Map containing the grouped elements * @throws NullPointerException if {@code classifier} is null. */ Map> groupBy(Function classifier); /** * Groups this {@code Traversable} into fixed size blocks. *

* Let length be the length of this Iterable. Then grouped is defined as follows: *

    *
  • If {@code this.isEmpty()}, the resulting {@code Iterator} is empty.
  • *
  • If {@code size <= length}, the resulting {@code Iterator} will contain {@code length / size} blocks of size * {@code size} and maybe a non-empty block of size {@code length % size}, if there are remaining elements.
  • *
  • If {@code size > length}, the resulting {@code Iterator} will contain one block of size {@code length}.
  • *
* Examples: *
     * 
     * [].grouped(1) = []
     * [].grouped(0) throws
     * [].grouped(-1) throws
     * [1,2,3,4].grouped(2) = [[1,2],[3,4]]
     * [1,2,3,4,5].grouped(2) = [[1,2],[3,4],[5]]
     * [1,2,3,4].grouped(5) = [[1,2,3,4]]
     * 
     * 
* * Please note that {@code grouped(int)} is a special case of {@linkplain #sliding(long, long)}, i.e. * {@code grouped(size)} is the same as {@code sliding(size, size)}. * * @param size a positive block size * @return A new Iterator of grouped blocks of the given size * @throws IllegalArgumentException if {@code size} is negative or zero */ Iterator> grouped(long size); /** * Checks if this Traversable is known to have a finite size. *

* This method should be implemented by classes only, i.e. not by interfaces. * * @return true, if this Traversable is known to hafe a finite size, false otherwise. */ boolean hasDefiniteSize(); /** * Returns the first element of a non-empty Traversable. * * @return The first element of this Traversable. * @throws NoSuchElementException if this is empty */ T head(); /** * Returns the first element of a non-empty Traversable as {@code Option}. * * @return {@code Some(element)} or {@code None} if this is empty. */ Option headOption(); /** * Dual of {@linkplain #tail()}, returning all elements except the last. * * @return a new instance containing all elements except the last. * @throws UnsupportedOperationException if this is empty */ Traversable init(); /** * Dual of {@linkplain #tailOption()}, returning all elements except the last as {@code Option}. * * @return {@code Some(traversable)} or {@code None} if this is empty. */ Option> initOption(); /** * Checks if this Traversable is empty. * * @return true, if this Traversable contains no elements, false otherwise. */ @Override boolean isEmpty(); /** * Each of Javaslang's collections may contain more than one element. * * @return {@code false} */ @Override default boolean isSingleValued() { return false; } /** * Checks if this Traversable can be repeatedly traversed. *

* This method should be implemented by classes only, i.e. not by interfaces. * * @return true, if this Traversable is known to be traversable repeatedly, false otherwise. */ boolean isTraversableAgain(); /** * An iterator by means of head() and tail(). Subclasses may want to override this method. * * @return A new Iterator of this Traversable elements. */ @Override default Iterator iterator() { final Traversable that = this; return new AbstractIterator() { Traversable traversable = that; @Override public boolean hasNext() { return !traversable.isEmpty(); } @Override public T getNext() { final T result = traversable.head(); traversable = traversable.tail(); return result; } }; } /** * Dual of {@linkplain #head()}, returning the last element. * * @return the last element. * @throws NoSuchElementException is this is empty */ default T last() { if (isEmpty()) { throw new NoSuchElementException("last of empty Traversable"); } else { final Iterator it = iterator(); T result = null; while (it.hasNext()) { result = it.next(); } return result; } } /** * Dual of {@linkplain #headOption()}, returning the last element as {@code Opiton}. * * @return {@code Some(element)} or {@code None} if this is empty. */ default Option lastOption() { return isEmpty() ? Option.none() : Option.some(last()); } /** * Computes the number of elements of this Traversable. *

* Same as {@link #size()}. * * @return the number of elements */ int length(); /** * Maps the elements of this {@code Traversable} to elements of a new type preserving their order, if any. * * @param mapper A mapper. * @param Component type of the target Traversable * @return a mapped Traversable * @throws NullPointerException if {@code mapper} is null */ @Override Traversable map(Function mapper); @Override Match.MatchValue.Of> match(); /** * Calculates the maximum of this elements according to their natural order. * * @return {@code Some(maximum)} of this elements or {@code None} if this is empty or this elements are not comparable */ @SuppressWarnings("unchecked") default Option max() { final Stream stream = Stream.ofAll(iterator()); if (isEmpty() || !(stream.head() instanceof Comparable)) { return Option.none(); } else { return stream.maxBy((o1, o2) -> ((Comparable) o1).compareTo(o2)); } } /** * Calculates the maximum of this elements using a specific comparator. * * @param comparator A non-null element comparator * @return {@code Some(maximum)} of this elements or {@code None} if this is empty * @throws NullPointerException if {@code comparator} is null */ default Option maxBy(Comparator comparator) { Objects.requireNonNull(comparator, "comparator is null"); if (isEmpty()) { return Option.none(); } else { final T value = reduce((t1, t2) -> comparator.compare(t1, t2) >= 0 ? t1 : t2); return Option.some(value); } } /** * Calculates the maximum of this elements within the co-domain of a specific function. * * @param f A function that maps this elements to comparable elements * @param The type where elements are compared * @return The element of type T which is the maximum within U * @throws NullPointerException if {@code f} is null. */ default > Option maxBy(Function f) { Objects.requireNonNull(f, "f is null"); if (isEmpty()) { return Option.none(); } else { final Iterator iter = iterator(); T tm = iter.next(); U um = f.apply(tm); while (iter.hasNext()) { final T t = iter.next(); final U u = f.apply(t); if (u.compareTo(um) > 0) { um = u; tm = t; } } return Option.some(tm); } } /** * Calculates the minimum of this elements according to their natural order. * * @return {@code Some(minimum)} of this elements or {@code None} if this is empty or this elements are not comparable */ @SuppressWarnings("unchecked") default Option min() { final Stream stream = Stream.ofAll(iterator()); if (isEmpty() || !(stream.head() instanceof Comparable)) { return Option.none(); } else { return stream.minBy((o1, o2) -> ((Comparable) o1).compareTo(o2)); } } /** * Calculates the minimum of this elements using a specific comparator. * * @param comparator A non-null element comparator * @return {@code Some(minimum)} of this elements or {@code None} if this is empty * @throws NullPointerException if {@code comparator} is null */ default Option minBy(Comparator comparator) { Objects.requireNonNull(comparator, "comparator is null"); if (isEmpty()) { return Option.none(); } else { final T value = reduce((t1, t2) -> comparator.compare(t1, t2) <= 0 ? t1 : t2); return Option.some(value); } } /** * Calculates the minimum of this elements within the co-domain of a specific function. * * @param f A function that maps this elements to comparable elements * @param The type where elements are compared * @return The element of type T which is the minimum within U * @throws NullPointerException if {@code f} is null. */ default > Option minBy(Function f) { Objects.requireNonNull(f, "f is null"); if (isEmpty()) { return Option.none(); } else { final Iterator iter = iterator(); T tm = iter.next(); U um = f.apply(tm); while (iter.hasNext()) { final T t = iter.next(); final U u = f.apply(t); if (u.compareTo(um) < 0) { um = u; tm = t; } } return Option.some(tm); } } /** * Joins the elements of this by concatenating their string representations. *

* This has the same effect as calling {@code mkString("", "", "")}. * * @return a new String */ default String mkString() { return mkString("", "", ""); } /** * Joins the string representations of this elements using a specific delimiter. *

* This has the same effect as calling {@code mkString(delimiter, "", "")}. * * @param delimiter A delimiter string put between string representations of elements of this * @return A new String */ default String mkString(CharSequence delimiter) { return mkString("", delimiter, ""); } /** * Joins the string representations of this elements using a specific delimiter, prefix and suffix. *

* Example: {@code List.of("a", "b", "c").mkString(", ", "Chars(", ")") = "Chars(a, b, c)"} * * @param prefix prefix of the resulting string * @param delimiter A delimiter string put between string representations of elements of this * @param suffix suffix of the resulting string * @return a new String */ default String mkString(CharSequence prefix, CharSequence delimiter, CharSequence suffix) { final StringBuilder builder = new StringBuilder(prefix); iterator().map(String::valueOf).intersperse(String.valueOf(delimiter)).forEach(builder::append); return builder.append(suffix).toString(); } /** * Creates a partition of this {@code Traversable} by splitting this elements in two in distinct tarversables * according to a predicate. * * @param predicate A predicate which classifies an element if it is in the first or the second traversable. * @return A disjoint union of two traversables. The first {@code Traversable} contains all elements that satisfy the given {@code predicate}, the second {@code Traversable} contains all elements that don't. The original order of elements is preserved. * @throws NullPointerException if predicate is null */ Tuple2, ? extends Traversable> partition(Predicate predicate); @Override Traversable peek(Consumer action); /** * Calculates the product of this elements. Supported component types are {@code Byte}, {@code Double}, {@code Float}, * {@code Integer}, {@code Long}, {@code Short}, {@code BigInteger} and {@code BigDecimal}. *

* Examples: *

     * 
     * List.empty().product()              // = 1
     * List.of(1, 2, 3).product()          // = 6
     * List.of(0.1, 0.2, 0.3).product()    // = 0.006
     * List.of("apple", "pear").product()  // throws
     * 
     * 
* * @return a {@code Number} representing the sum of this elements * @throws UnsupportedOperationException if this elements are not numeric */ @SuppressWarnings("unchecked") default Number product() { if (isEmpty()) { return 1; } else { final Traversable objects = isTraversableAgain() ? this : toStream(); final Object head = objects.head(); if (head instanceof Integer || head instanceof Short || head instanceof Byte) { return ((Traversable) objects).toJavaStream().mapToInt(Number::intValue).reduce(1, (i1, i2) -> i1 * i2); } else if (head instanceof Double || head instanceof Float || head instanceof BigDecimal) { return ((Traversable) objects).toJavaStream().mapToDouble(Number::doubleValue).reduce(1.0, (d1, d2) -> d1 * d2); } else if (head instanceof Long || head instanceof BigInteger) { return ((Traversable) objects).toJavaStream().mapToLong(Number::longValue).reduce(1L, (l1, l2) -> l1 * l2); } else { throw new UnsupportedOperationException("not numeric"); } } } /** * Accumulates the elements of this Traversable by successively calling the given operation {@code op} from the left. * * @param op A BiFunction of type T * @return the reduced value. * @throws NoSuchElementException if this is empty * @throws NullPointerException if {@code op} is null */ @Override default T reduceLeft(BiFunction op) { Objects.requireNonNull(op, "op is null"); if (isEmpty()) { throw new NoSuchElementException("reduceLeft on Nil"); } else { return tail().foldLeft(head(), op); } } /** * Shortcut for {@code isEmpty() ? Option.none() : Option.some(reduceLeft(op))}. * * @param op A BiFunction of type T * @return a reduced value * @throws NullPointerException if {@code op} is null */ @Override default Option reduceLeftOption(BiFunction op) { Objects.requireNonNull(op, "op is null"); return isEmpty() ? Option.none() : Option.some(reduceLeft(op)); } /** * Accumulates the elements of this Traversable by successively calling the given operation {@code op} from the right. * * @param op An operation of type T * @return the reduced value. * @throws NoSuchElementException if this is empty * @throws NullPointerException if {@code op} is null */ @Override default T reduceRight(BiFunction op) { Objects.requireNonNull(op, "op is null"); if (isEmpty()) { throw new NoSuchElementException("reduceRight on empty"); } else { return iterator().reduceRight(op); } } /** * Shortcut for {@code isEmpty() ? Option.none() : Option.some(reduceRight(op))}. * * @param op An operation of type T * @return a reduced value * @throws NullPointerException if {@code op} is null */ @Override default Option reduceRightOption(BiFunction op) { Objects.requireNonNull(op, "op is null"); return isEmpty() ? Option.none() : Option.some(reduceRight(op)); } /** * Replaces the first occurrence (if exists) of the given currentElement with newElement. * * @param currentElement An element to be substituted. * @param newElement A replacement for currentElement. * @return a Traversable containing all elements of this where the first occurrence of currentElement is replaced with newELement. */ Traversable replace(T currentElement, T newElement); /** * Replaces all occurrences of the given currentElement with newElement. * * @param currentElement An element to be substituted. * @param newElement A replacement for currentElement. * @return a Traversable containing all elements of this where all occurrences of currentElement are replaced with newELement. */ Traversable replaceAll(T currentElement, T newElement); /** * Keeps all occurrences of the given elements from this. * * @param elements Elements to be kept. * @return a Traversable containing all occurrences of the given elements. * @throws NullPointerException if {@code elements} is null */ Traversable retainAll(Iterable elements); /** * Computes a prefix scan of the elements of the collection. * * Note: The neutral element z may be applied more than once. * * @param zero neutral element for the operator op * @param operation the associative operator for the scan * @return a new traversable collection containing the prefix scan of the elements in this traversable collection * @throws NullPointerException if {@code operation} is null. */ Traversable scan(T zero, BiFunction operation); /** * Produces a collection containing cumulative results of applying the * operator going left to right. * * Note: will not terminate for infinite-sized collections. * * Note: might return different results for different runs, unless the * underlying collection type is ordered. * * @param the type of the elements in the resulting collection * @param zero the initial value * @param operation the binary operator applied to the intermediate result and the element * @return collection with intermediate results * @throws NullPointerException if {@code operation} is null. */ Traversable scanLeft(U zero, BiFunction operation); /** * Produces a collection containing cumulative results of applying the * operator going right to left. The head of the collection is the last * cumulative result. * * Note: will not terminate for infinite-sized collections. * * Note: might return different results for different runs, unless the * underlying collection type is ordered. * * @param the type of the elements in the resulting collection * @param zero the initial value * @param operation the binary operator applied to the intermediate result and the element * @return collection with intermediate results * @throws NullPointerException if {@code operation} is null. */ Traversable scanRight(U zero, BiFunction operation); /** * Computes the number of elements of this Traversable. *

* Same as {@link #length()}. * * @return the number of elements */ default int size() { return length(); } /** * Slides a window of a specific {@code size} and step size 1 over this {@code Traversable} by calling * {@link #sliding(long, long)}. * * @param size a positive window size * @return a new Iterator of windows of a specific size using step size 1 * @throws IllegalArgumentException if {@code size} is negative or zero */ Iterator> sliding(long size); /** * Slides a window of a specific {@code size} and {@code step} size over this {@code Traversable}. *

* Examples: *

     * 
     * [].sliding(1,1) = []
     * [1,2,3,4,5].sliding(2,3) = [[1,2],[4,5]]
     * [1,2,3,4,5].sliding(2,4) = [[1,2],[5]]
     * [1,2,3,4,5].sliding(2,5) = [[1,2]]
     * [1,2,3,4].sliding(5,3) = [[1,2,3,4],[4]]
     * 
     * 
* * @param size a positive window size * @param step a positive step size * @return a new Iterator of windows of a specific size using a specific step size * @throws IllegalArgumentException if {@code size} or {@code step} are negative or zero */ Iterator> sliding(long size, long step); /** * Returns a tuple where the first element is the longest prefix of elements that satisfy the given * {@code predicate} and the second element is the remainder. * * @param predicate A predicate. * @return a Tuple containing the longest prefix of elements that satisfy p and the remainder. * @throws NullPointerException if {@code predicate} is null */ Tuple2, ? extends Traversable> span(Predicate predicate); /** * Calculates the sum of this elements. Supported component types are {@code Byte}, {@code Double}, {@code Float}, * {@code Integer}, {@code Long}, {@code Short}, {@code BigInteger} and {@code BigDecimal}. *

* Examples: *

     * 
     * List.empty().sum()              // = 0
     * List.of(1, 2, 3).sum()          // = 6
     * List.of(0.1, 0.2, 0.3).sum()    // = 0.6
     * List.of("apple", "pear").sum()  // throws
     * 
     * 
* * @return a {@code Number} representing the sum of this elements * @throws UnsupportedOperationException if this elements are not numeric */ @SuppressWarnings("unchecked") default Number sum() { if (isEmpty()) { return 0; } else { final Traversable objects = isTraversableAgain() ? this : toStream(); final Object head = objects.head(); if (head instanceof Integer || head instanceof Short || head instanceof Byte) { return ((Traversable) objects).toJavaStream().mapToInt(Number::intValue).sum(); } else if (head instanceof Double || head instanceof Float || head instanceof BigDecimal) { return ((Traversable) objects).toJavaStream().mapToDouble(Number::doubleValue).sum(); } else if (head instanceof Long || head instanceof BigInteger) { return ((Traversable) objects).toJavaStream().mapToLong(Number::longValue).sum(); } else { throw new UnsupportedOperationException("not numeric"); } } } /** * Drops the first element of a non-empty Traversable. * * @return A new instance of Traversable containing all elements except the first. * @throws UnsupportedOperationException if this is empty */ Traversable tail(); /** * Drops the first element of a non-empty Traversable and returns an {@code Option}. * * @return {@code Some(traversable)} or {@code None} if this is empty. */ Option> tailOption(); /** * Takes the first n elements of this or all elements, if this length < n. *

* The result is equivalent to {@code sublist(0, max(0, min(length(), n)))} but does not throw if {@code n < 0} or * {@code n > length()}. *

* In the case of {@code n < 0} the empty instance is returned, in the case of {@code n > length()} this is returned. * * @param n The number of elements to take. * @return A new instance consisting the first n elements of this or all elements, if this has less than n elements. */ Traversable take(long n); /** * Takes the last n elements of this or all elements, if this length < n. *

* The result is equivalent to {@code sublist(max(0, min(length(), length() - n)), n)}, i.e. takeRight will not * throw if {@code n < 0} or {@code n > length()}. *

* In the case of {@code n < 0} the empty instance is returned, in the case of {@code n > length()} this is returned. * * @param n The number of elements to take. * @return A new instance consisting the first n elements of this or all elements, if this has less than n elements. */ Traversable takeRight(long n); /** * Takes elements until the predicate holds for the current element. *

* Note: This is essentially the same as {@code takeWhile(predicate.negate())}. It is intended to be used with * method references, which cannot be negated directly. * * @param predicate A condition tested subsequently for this elements. * @return a new instance consisting of all elements until the first which does satisfy the given predicate. * @throws NullPointerException if {@code predicate} is null */ Traversable takeUntil(Predicate predicate); /** * Takes elements while the predicate holds for the current element. * * @param predicate A condition tested subsequently for the contained elements. * @return a new instance consisting of all elements until the first which does not satisfy the given predicate. * @throws NullPointerException if {@code predicate} is null */ Traversable takeWhile(Predicate predicate); /** * Unzips this elements by mapping this elements to pairs which are subsequently split into two distinct * sets. * * @param unzipper a function which converts elements of this to pairs * @param 1st element type of a pair returned by unzipper * @param 2nd element type of a pair returned by unzipper * @return A pair of set containing elements split by unzipper * @throws NullPointerException if {@code unzipper} is null */ Tuple2, ? extends Traversable> unzip( Function> unzipper); /** * Unzips this elements by mapping this elements to triples which are subsequently split into three distinct * sets. * * @param unzipper a function which converts elements of this to pairs * @param 1st element type of a triplet returned by unzipper * @param 2nd element type of a triplet returned by unzipper * @param 3rd element type of a triplet returned by unzipper * @return A triplet of set containing elements split by unzipper * @throws NullPointerException if {@code unzipper} is null */ Tuple3, ? extends Traversable, ? extends Traversable> unzip3( Function> unzipper); /** * Returns a traversable formed from this traversable and another Iterable collection by combining * corresponding elements in pairs. If one of the two iterables is longer than the other, its remaining elements * are ignored. *

* The length of the returned traversable is the minimum of the lengths of this traversable and {@code that} * iterable. * * @param The type of the second half of the returned pairs. * @param that The Iterable providing the second half of each result pair. * @return a new traversable containing pairs consisting of corresponding elements of this traversable and {@code that} iterable. * @throws NullPointerException if {@code that} is null */ Traversable> zip(Iterable that); /** * Returns a traversable formed from this traversable and another Iterable by combining corresponding elements in * pairs. If one of the two collections is shorter than the other, placeholder elements are used to extend the * shorter collection to the length of the longer. *

* The length of the returned traversable is the maximum of the lengths of this traversable and {@code that} * iterable. *

* Special case: if this traversable is shorter than that elements, and that elements contains duplicates, the * resulting traversable may be shorter than the maximum of the lengths of this and that because a traversable * contains an element at most once. *

* If this Traversable is shorter than that, thisElem values are used to fill the result. * If that is shorter than this Traversable, thatElem values are used to fill the result. * * @param The type of the second half of the returned pairs. * @param that The Iterable providing the second half of each result pair. * @param thisElem The element to be used to fill up the result if this traversable is shorter than that. * @param thatElem The element to be used to fill up the result if that is shorter than this traversable. * @return A new traversable containing pairs consisting of corresponding elements of this traversable and that. * @throws NullPointerException if {@code that} is null */ Traversable> zipAll(Iterable that, T thisElem, U thatElem); /** * Zips this traversable with its indices. * * @return A new traversable containing all elements of this traversable paired with their index, starting with 0. */ Traversable> zipWithIndex(); }