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

com.simplaex.bedrock.Seq Maven / Gradle / Ivy

package com.simplaex.bedrock;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import java.io.Serializable;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * An immutable sequence.
 *
 * @param  The type of the Elements contained in this Sequence.
 */
@Immutable
@SuppressWarnings({"unused", "WeakerAccess"})
public abstract class Seq implements
  Serializable,
  RandomAccess,
  SequenceMethods, BiPredicate, Seq>,
  Container,
  IntFunction {

  private int hashCode = 0;

  public abstract E get(@Nonnegative final int index);

  @Override
  public E apply(@Nonnegative final int index) {
    return get(index);
  }

  @Override
  public boolean isEmpty() {
    return length() == 0;
  }

  @Override
  @Nonnull
  public Seq shuffled(@Nonnull final Random random) {
    Objects.requireNonNull(random, "the supplied 'random' generator must not be null");
    final Object[] array = toArray();
    final int len = array.length;
    for (int i = 0; i < len; i += 1) {
      swap(array, i, random.nextInt(len));
    }
    return new SeqSimple<>(array);
  }

  public E draw(final Random random) throws NoSuchElementException {
    if (isEmpty()) {
      throw new NoSuchElementException("drawing from an empty set");
    }
    final int ix = random.nextInt(size());
    return get(ix);
  }

  @Nonnull
  public abstract Seq sortedBy(@Nonnull final Comparator comparator);

  @Nonnull
  public > Seq sortedOn(@Nonnull final Function function) {
    Objects.requireNonNull(function, "'function' must not be null");
    return sortedBy(Comparator.comparing(function));
  }

  @Nonnull
  public abstract E[] toArray(@Nonnull final Class clazz);

  @Nonnull
  public abstract Object[] toArray();

  @Override
  @Nonnull
  public String asString(final String delimiter) {
    return stream().map(Objects::toString).collect(Collectors.joining(delimiter));
  }

  @Nonnegative
  public int count(@Nullable final E e) {
    final int len = length();
    int c = 0;
    for (int i = 0; i < len; i += 1) {
      final E el = get(i);
      if (el == e || el != null && el.equals(e)) {
        c += 1;
      }
    }
    return c;
  }

  @Nonnegative
  public int countBy(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    final int len = length();
    int c = 0;
    for (int i = 0; i < len; i += 1) {
      final E el = get(i);
      if (predicate.test(el)) {
        c += 1;
      }
    }
    return c;
  }

  public int find(@Nullable final E e) {
    final int len = length();
    for (int i = 0; i < len; i += 1) {
      final E el = get(i);
      if (el == e || el != null && el.equals(e)) {
        return i;
      }
    }
    return -1;
  }

  public int findBy(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    final int len = length();
    for (int i = 0; i < len; i += 1) {
      final E element = get(i);
      if (predicate.test(element)) {
        return i;
      }
    }
    return -1;
  }

  public Optional findFirst(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    final int len = length();
    for (int i = 0; i < len; i += 1) {
      final E element = get(i);
      if (predicate.test(element)) {
        return Optional.ofNullable(element);
      }
    }
    return Optional.empty();
  }

  @Override
  public boolean contains(@Nullable final E e) {
    return find(e) > -1;
  }

  @Override
  public boolean exists(@Nonnull final Predicate predicate) {
    return findBy(predicate) > -1;
  }

  @Override
  public boolean forAll(@Nonnull final Predicate predicate) {
    return countBy(predicate) == length();
  }

  void checkBounds(final int index) {
    if (index >= length() || index < 0) {
      throw new IndexOutOfBoundsException();
    }
  }

  @Nonnull
  public  Seq map(@Nonnull final Function function) {
    Objects.requireNonNull(function, "'function' must not be null");
    final Object[] array = new Object[length()];
    int i = 0;
    for (final E e : this) {
      array[i++] = function.apply(e);
    }
    return new SeqSimple<>(array);
  }

  @Nonnull
  public  Seq flatMap(@Nonnull final Function> function) {
    Objects.requireNonNull(function, "'function' must not be null");
    @SuppressWarnings("unchecked") final Seq[] array = (Seq[]) new Seq[length()];
    int i = 0;
    int c = 0;
    for (final E e : this) {
      final Seq result = function.apply(e);
      c += result.length();
      array[i++] = result;
    }
    final Object[] resultArray = new Object[c];
    i = 0;
    for (final Seq s : array) {
      for (final F e : s) {
        resultArray[i++] = e;
      }
    }
    return new SeqSimple<>(resultArray);
  }

  @Nonnull
  public  Seq flatMapOptional(@Nonnull final Function> function) {
    Objects.requireNonNull(function, "'function' must not be null");
    @SuppressWarnings("unchecked") final Seq[] array = (Seq[]) new Seq[length()];
    final SeqBuilder resultBuilder = Seq.builder();
    for (final E e : this) {
      final Optional result = function.apply(e);
      result.ifPresent(resultBuilder::add);
    }
    return resultBuilder.build();
  }

  @Nonnull
  public  Seq flatMapIterable(@Nonnull final Function> function) {
    Objects.requireNonNull(function, "'function' must not be null");
    @SuppressWarnings("unchecked") final Seq[] array = (Seq[]) new Seq[length()];
    final SeqBuilder resultBuilder = Seq.builder();
    for (final E e : this) {
      resultBuilder.addElements(function.apply(e));
    }
    return resultBuilder.build();
  }

  @Nonnull
  public  Seq> zip(@Nonnull final Seq a) {
    return zipWith(Pair::new, a);
  }

  @Nonnull
  public  Seq zipWith(
    final @Nonnull BiFunction function,
    final @Nonnull Seq sequence
  ) {
    Objects.requireNonNull(function, "'function' must not be null");
    Objects.requireNonNull(sequence);
    final int len = Math.min(length(), sequence.length());
    final Object[] arr = new Object[len];
    for (int i = 0; i < len; i += 1) {
      arr[i] = function.apply(get(i), sequence.get(i));
    }
    return new SeqSimple<>(arr);
  }

  @Nonnull
  public Seq> zipWithIndex() {
    return Seq.rangeExclusive(0, length()).zip(this);
  }

  public  A foldl(@Nonnull final BiFunction function, final A startValue) {
    Objects.requireNonNull(function, "'function' must not be null");
    A acc = startValue;
    for (int i = 0; i < length(); i += 1) {
      acc = function.apply(acc, get(i));
    }
    return acc;
  }

  public E foldl1(@Nonnull final BiFunction function) {
    return foldl(function, head());
  }

  public  A foldr(@Nonnull final BiFunction function, final A startValue) {
    Objects.requireNonNull(function, "'function' must not be null");
    A acc = startValue;
    for (int i = length() - 1; i >= 0; i -= 1) {
      acc = function.apply(get(i), acc);
    }
    return acc;
  }

  public E foldr1(@Nonnull final BiFunction function) {
    return foldr(function, last());
  }

  @Override
  @Nonnull
  public Pair, Seq> partitionBy(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    final int sizeHint = length() / 2 + 1;
    final SeqBuilder b1 = Seq.builder(sizeHint);
    final SeqBuilder b2 = Seq.builder(sizeHint);
    forEach(x -> {
      if (predicate.test(x)) {
        b1.add(x);
      } else {
        b2.add(x);
      }
    });
    return Pair.of(b1.result(), b2.result());
  }

  @SuppressWarnings("unchecked")
  public E maximum() {
    try {
      return (E) maximum((Seq) this);
    } catch (final ClassCastException exc) {
      return null;
    }
  }

  @SuppressWarnings("unchecked")
  public E minimum() {
    try {
      return (E) minimum((Seq) this);
    } catch (final ClassCastException exc) {
      return null;
    }
  }

  public E maximumBy(final Comparator comparator) {
    return foldl1((left, right) -> comparator.compare(left, right) < 0 ? right : left);
  }

  public E minimumBy(final Comparator comparator) {
    return foldl1((left, right) -> comparator.compare(left, right) > 0 ? right : left);
  }

  @Override
  @Nonnull
  public Seq> group() {
    return groupBy(Objects::equals);
  }

  @Override
  @Nonnull
  public Seq> groupBy(@Nonnull final BiPredicate operator) {
    Objects.requireNonNull(operator, "'operator' must not be null");
    if (isEmpty()) {
      return Seq.empty();
    }
    final SeqBuilder> b1 = Seq.builder();
    final SeqBuilder b2 = Seq.builder();
    E previous = head();
    b2.add(previous);
    for (int i = 1; i < size(); i += 1) {
      final E current = get(i);
      if (!operator.test(previous, current)) {
        b1.add(b2.result());
        b2.clear();
      }
      b2.add(current);
      previous = current;
    }
    if (!b2.isEmpty()) {
      b1.add(b2.result());
    }
    return b1.result();
  }

  @Nonnull
  @SuppressWarnings("unchecked")
  public  Seq filter(@Nonnull final Class clazz) {
    final Seq res = filter(element -> element != null && clazz.isAssignableFrom(element.getClass()));
    return (Seq) res;
  }

  @Override
  @Nonnull
  public Seq filter(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    final int sizeHint = length() / 2;
    final SeqBuilder b = Seq.builder(sizeHint);
    forEach(x -> {
      if (predicate.test(x)) {
        b.add(x);
      }
    });
    return b.result();
  }

  @Override
  @Nonnull
  public Seq filterNot(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    return filter(predicate.negate());
  }

  @Override
  @Nonnull
  public Seq takeWhile(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    int i = 0;
    while (i < length() && predicate.test(get(i))) {
      i += 1;
    }
    return take(i);
  }

  @Override
  @Nonnull
  public Seq takeWhileView(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    int i = 0;
    while (i < length() && predicate.test(get(i))) {
      i += 1;
    }
    return takeView(i);
  }

  @Override
  @Nonnull
  public Seq dropWhile(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    int i = 0;
    while (i < length() && predicate.test(get(i))) {
      i += 1;
    }
    return drop(i);
  }

  @Override
  @Nonnull
  public Seq dropWhileView(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    int i = 0;
    while (i < length() && predicate.test(get(i))) {
      i += 1;
    }
    return dropView(i);
  }

  @Override
  @Nonnull
  public Pair, Seq> breakBy(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    final int ix = findBy(predicate);
    if (ix < 0) {
      return Pair.of(this, Seq.empty());
    } else if (ix == 0) {
      return Pair.of(Seq.empty(), this);
    } else {
      return Pair.of(subSequence(0, ix), subSequence(ix, length()));
    }
  }

  @Override
  @Nonnull
  public Pair, Seq> breakByView(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    final int ix = findBy(predicate);
    if (ix < 0) {
      return Pair.of(this, Seq.empty());
    } else if (ix == 0) {
      return Pair.of(Seq.empty(), this);
    } else {
      return Pair.of(subSequenceView(0, ix), subSequenceView(ix, length()));
    }
  }

  @Override
  @Nonnull
  public Pair, Seq> spanBy(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    return breakBy(predicate.negate());
  }

  @Override
  @Nonnull
  public Pair, Seq> spanByView(@Nonnull final Predicate predicate) {
    Objects.requireNonNull(predicate, "'predicate' must not be null");
    return breakByView(predicate.negate());
  }

  @Override
  @Nonnull
  public Seq> inits() {
    final int len = length();
    @SuppressWarnings("unchecked") final Seq[] seqs = (Seq[]) new Seq[len];
    for (int i = 0; i < len; i += 1) {
      seqs[i] = take(i + 1);
    }
    return new SeqSimple<>(seqs);
  }

  @Override
  @Nonnull
  public Seq> initsView() {
    final int len = length();
    @SuppressWarnings("unchecked") final Seq[] seqs = (Seq[]) new Seq[len];
    for (int i = 0; i < len; i += 1) {
      seqs[i] = takeView(i + 1);
    }
    return new SeqSimple<>(seqs);
  }

  @Override
  @Nonnull
  public Seq> tails() {
    final int len = length();
    @SuppressWarnings("unchecked") final Seq[] seqs = (Seq[]) new Seq[len];
    for (int i = 0; i < len; i += 1) {
      seqs[i] = takeRight(i + 1);
    }
    return new SeqSimple<>(seqs);
  }

  @Override
  @Nonnull
  public Seq> tailsView() {
    final int len = length();
    @SuppressWarnings("unchecked") final Seq[] seqs = (Seq[]) new Seq[len];
    for (int i = 0; i < len; i += 1) {
      seqs[i] = takeRightView(i + 1);
    }
    return new SeqSimple<>(seqs);
  }

  public E head() {
    return get(0);
  }

  public E last() {
    return get(length() - 1);
  }

  @Nonnull
  public Optional headOptional() {
    if (isEmpty()) {
      return Optional.empty();
    }
    return Optional.of(head());
  }

  @Nonnull
  public Optional lastOptional() {
    if (isEmpty()) {
      return Optional.empty();
    }
    return Optional.of(last());
  }

  @Nonnull
  public Seq intercalate(@Nonnull final Seq seq) {
    if (isEmpty()) {
      return this;
    }
    final int targetSize = (seq.size() + 1) * size() - seq.size();
    final Object[] targetArray = new Object[targetSize];
    targetArray[0] = head();
    int targetIndex = 1;
    for (int i = 1; i < size(); i += 1) {
      for (int j = 0; j < seq.size(); j += 1) {
        targetArray[targetIndex++] = seq.get(j);
      }
      targetArray[targetIndex++] = get(i);
    }
    return new SeqSimple<>(targetArray);
  }

  @Nonnull
  public Seq intersperse(final E e) {
    if (isEmpty()) {
      return this;
    }
    final int targetSize = size() * 2 - 1;
    final Object[] targetArray = new Object[targetSize];
    targetArray[0] = head();
    int targetIndex = 1;
    for (int i = 1; i < size(); i += 1) {
      targetArray[targetIndex++] = e;
      targetArray[targetIndex++] = get(i);
    }
    return new SeqSimple<>(targetArray);
  }

  /**
   * Returns a copy of this Seq with no duplicates.
   * 

* Order is maintained. */ @Nonnull @Override public Seq distinct() { final HashSet elements = new HashSet<>(); final SeqBuilder builder = Seq.builder(size()); forEach(element -> { if (!elements.contains(element)) { builder.add(element); elements.add(element); } }); return builder.result(); } /** * Returns a Seq with the elements from the given Seq removed. *

* Order is maintained, but the resuling Seq is not distinct; if this Seq contains duplicates then the result * may contain duplicates too. */ public Seq without(final Seq seq) { return filter(element -> !seq.contains(element)); } /** * Returns a distinct Seq that contains the elements from both this Seq and the given Seq. *

* Order is maintained, but there are no duplicates. */ public Seq union(final Seq seq) { final HashSet elements = new HashSet<>(); final SeqBuilder builder = Seq.builder(size()); final Consumer appender = element -> { if (!elements.contains(element)) { builder.add(element); elements.add(element); } }; forEach(appender); seq.forEach(appender); return builder.result(); } /** * Returns a distinct Seq that contains only the elements that occur in both sets. *

* Order is maintained. */ public Seq intersect(final Seq seq) { return union(seq).filter(e -> contains(e) && seq.contains(e)); } @Override public boolean equals(final @Nullable Object that) { if (this == that) { return true; } if (!(that instanceof Seq)) { return false; } final int len = length(); @SuppressWarnings("unchecked") final Seq thatSeq = (Seq) that; if (len != thatSeq.length()) { return false; } for (int i = 0; i < len; i += 1) { final E thisElement = get(i); final E thatElement = thatSeq.get(i); if (!(thisElement == thatElement || thisElement != null && thisElement.equals(thatElement))) { return false; } } return true; } @Override public final int hashCode() { if (hashCode == 0) { hashCode = calculateHashCode(); } return hashCode; } int calculateHashCode() { int result = 1; for (final E element : this) { result = 31 * result + (element == null ? 0 : element.hashCode()); } return result; } @Override public String toString() { return stream().map(Objects::toString).collect(Collectors.joining(", ", "[", "]")); } static void swap(final E[] array, final int i, final int j) { final E src = array[i]; array[i] = array[j]; array[j] = src; } static void reverse(final @Nonnull E[] array) { final int len = array.length; final int halfLen = len / 2; for (int i = 0, j = len - 1; i < halfLen; i += 1, j -= 1) { swap(array, i, j); } } @Nonnull @Override public Iterator> permutationsIterator() { return new PermutationIterator<>(this); } @Nonnull @Override public Seq> permutations() { return permutationsStream().collect(collector()); } @Nonnull @Override public Iterator iterator() { return new Iterator() { private int current = 0; @Override public boolean hasNext() { return current < length(); } @Override public E next() { return get(current++); } }; } @Nonnull public Iterator reverseIterator() { return reversed().iterator(); } @Nonnull public List toList() { return new AbstractList() { @Override public E get(final int index) { return Seq.this.get(index); } @Override public int size() { return length(); } }; } public static Collector, Seq> collector() { return new Collector, Seq>() { @Override public Supplier> supplier() { return Seq::builder; } @Override public BiConsumer, T> accumulator() { return SeqBuilder::add; } @Override public BinaryOperator> combiner() { return SeqBuilder::addElements; } @Override public Function, Seq> finisher() { return SeqBuilder::result; } @Override public java.util.Set characteristics() { return Collections.emptySet(); } }; } @Nonnull public Mapping> toMap(@Nonnull final Function groupingFunction) { Objects.requireNonNull(groupingFunction, "'groupingFunction' must not be null"); final Map> map = new HashMap<>(); boolean allComparable = true; for (final E element : this) { final K key = groupingFunction.apply(element); allComparable = allComparable && key instanceof Comparable; if (!map.containsKey(key)) { map.put(key, Seq.builder()); } map.get(key).add(element); } if (map.isEmpty()) { return Mapping.empty(); } final Map> finalMap = new HashMap<>(); map.forEach((key, builder) -> finalMap.put(key, builder.result())); return Mapping.wrap(finalMap); } @Nonnull public > ArrayMap> toArrayMap(@Nonnull final Function groupingFunction) { Objects.requireNonNull(groupingFunction, "'groupingFunction' must not be null"); final TreeMap> map = new TreeMap<>(); for (final E element : this) { final K key = groupingFunction.apply(element); if (!map.containsKey(key)) { map.put(key, Seq.builder()); } map.get(key).add(element); } if (map.isEmpty()) { return ArrayMap.empty(); } final Object[] keys = Seq.ofCollectionInternal(map.keySet()).backingArray; final Object[] values = new Object[keys.length]; for (int i = 0; i < keys.length; i += 1) { //noinspection SuspiciousMethodCalls values[i] = map.get(keys[i]).result(); } return new ArrayMap<>(keys, values); } @SuppressWarnings("unchecked") @Nonnull public static Seq empty() { return (Seq) SeqEmpty.EMPTY; } @SafeVarargs @Nonnull public static Seq of(@Nonnull final E... es) { Objects.requireNonNull(es); if (es.length == 0) { return empty(); } return new SeqSimple<>(es); } @SafeVarargs @Nonnull public static Seq seq(@Nonnull final E... es) { return ofArray(es); } @Nonnull public static Seq ofArray(@Nonnull final E[] array) { Objects.requireNonNull(array); if (array.length == 0) { return empty(); } return new SeqSimple<>(array.clone()); } @Nonnull static SeqSimple ofArrayZeroCopyInternal(@Nonnull final Object[] array) { return new SeqSimple<>(array); } @Nonnull public static Seq ofCollection(@Nonnull final Collection collection) { Objects.requireNonNull(collection); if (collection.isEmpty()) { return empty(); } return ofCollectionInternal(collection); } @Nonnull static SeqSimple ofCollectionInternal(@Nonnull final Collection collection) { final Object[] array = new Object[collection.size()]; int i = 0; for (final E e : collection) { array[i++] = e; } return new SeqSimple<>(array); } @Nonnull public static Seq ofIterable(@Nonnull final Iterable iterable) { Objects.requireNonNull(iterable); final SeqBuilder builder = new SeqBuilder<>(); iterable.forEach(builder::add); return builder.result(); } @Nonnull public static Seq ofIterator(@Nonnull final Iterator iterator) { Objects.requireNonNull(iterator); final SeqBuilder builder = new SeqBuilder<>(); while (iterator.hasNext()) { builder.add(iterator.next()); } return builder.result(); } @Nonnull public static Seq ofPair(@Nonnull final Pair pair) { Objects.requireNonNull(pair, "'pair' must not be null"); return Seq.builder().addAll(pair.fst(), pair.snd()).result(); } @Nonnull public static Seq ofString(@Nonnull final String string) { Objects.requireNonNull(string); final Character[] array = new Character[string.length()]; for (int i = 0; i < array.length; i += 1) { array[i] = string.charAt(i); } return new SeqSimple<>(array); } public interface WithIndexConsumer { void consume(int index, E element); } public void forEach(final WithIndexConsumer consumer) { for (int i = 0; i < size(); i += 1) { consumer.consume(i, get(i)); } } @Nonnull public static Seq codepointsOfString(@Nonnull final String string) { final char[] array = string.toCharArray(); final SeqBuilder b = builder(); for (int i = 0; i < array.length; i += 1) { final char c1 = array[i]; if (Character.isHighSurrogate(c1)) { i += 1; if (i < array.length) { final char c2 = array[i]; if (Character.isLowSurrogate(c2)) { final int codepoint = Character.toCodePoint(c1, c2); b.add(codepoint); } } } else { b.add((int) c1); } } return b.result(); } @SafeVarargs @Nonnull public static Seq concat(@Nonnull final Seq... seqs) { Objects.requireNonNull(seqs); int size = 0; for (final Seq seq : seqs) { size += seq.length(); } final Object[] array = new Object[size]; int i = 0; for (final Seq seq : seqs) { for (final E elem : seq) { array[i++] = elem; } } return new SeqSimple<>(array); } @Nonnull public static SeqBuilder builder() { return new SeqBuilder<>(); } @Nonnull public static SeqBuilder builder(final int sizeHint) { return new SeqBuilder<>(sizeHint); } @Nonnegative public static Seq ofGenerator(@Nonnull final IntFunction function, @Nonnegative final int length) { Objects.requireNonNull(function, "'function' must not be null."); return new SeqGenerated<>(function, length); } public static Seq wrap(@Nonnull final char[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final boolean[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final byte[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final short[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final int[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final long[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final float[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final double[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final Character[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final Boolean[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final Byte[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final Short[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final Integer[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final Long[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final Float[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final Double[] array) { if (array.length == 0) { return Seq.empty(); } return ofGenerator(ix -> array[ix], array.length); } public static Seq wrap(@Nonnull final List list) { if (list.isEmpty()) { return Seq.empty(); } return ofGenerator(list::get, list.size()); } public static Seq wrap(@Nonnull final BitSet bitSet) { if (bitSet.isEmpty()) { return Seq.empty(); } return ofGenerator(bitSet::get, bitSet.length()); } public static Seq wrap(@Nonnull final String string) { if (string.isEmpty()) { return Seq.empty(); } return ofGenerator(string::charAt, string.length()); } public static > E minimum(final Seq seq) { if (seq instanceof SeqSimpleSorted) { return seq.head(); } Objects.requireNonNull(seq, "'seq' must not be null"); return seq.minimumBy(Comparable::compareTo); } public static > E maximum(final Seq seq) { if (seq instanceof SeqSimpleSorted) { return seq.last(); } Objects.requireNonNull(seq, "'seq' must not be null"); return seq.maximumBy(Comparable::compareTo); } public static boolean any(final Seq seq) { return seq.exists(x -> x); } public static boolean all(final Seq seq) { return seq.forAll(x -> x); } public static int intSum(final Seq seq) { Objects.requireNonNull(seq, "'seq' must not be null"); return seq.foldl(Operators::plus, 0); } public static long longSum(final Seq seq) { Objects.requireNonNull(seq, "'seq' must not be null"); return seq.foldl(Operators::plus, 0L); } public static double doubleSum(final Seq seq) { Objects.requireNonNull(seq, "'seq' must not be null"); return seq.foldl(Operators::plus, 0.0); } public static int intProduct(final Seq seq) { Objects.requireNonNull(seq, "'seq' must not be null"); return seq.foldl(Operators::times, 1); } public static long longProduct(final Seq seq) { Objects.requireNonNull(seq, "'seq' must not be null"); return seq.foldl(Operators::times, 1L); } public static double doubleProduct(final Seq seq) { Objects.requireNonNull(seq, "'seq' must not be null"); return seq.foldl(Operators::times, 1.0); } public static boolean and(final Seq seq) { Objects.requireNonNull(seq, "'seq' must not be null"); return seq.foldr((left, right) -> left && right, true); } public static boolean or(final Seq seq) { Objects.requireNonNull(seq, "'seq' must not be null"); return seq.foldr((left, right) -> left || right, false); } public static int commonPrefixLength(final Seq as, final Seq bs) { Objects.requireNonNull(as, "'as' must not be null"); Objects.requireNonNull(bs, "'bs' must not be null"); final int length = Math.min(as.size(), bs.size()); int commonPrefixLength = 0; for (int i = 0; i < length; i += 1) { final A a = as.get(i); final B b = bs.get(i); if (a == null) { if (b == null) { commonPrefixLength += 1; continue; } break; } if (a.equals(b)) { commonPrefixLength += 1; continue; } break; } return commonPrefixLength; } public static Seq commonPrefix(final Seq as, final Seq bs) { final int commonPrefixLength = commonPrefixLength(as, bs); return as.subSequence(0, commonPrefixLength); } public static Seq commonPrefixView(final Seq as, final Seq bs) { final int commonPrefixLength = commonPrefixLength(as, bs); return as.subSequenceView(0, commonPrefixLength); } public static Seq rangeInclusive(final int from, final int to) { if (from <= to) { return ofGenerator(index -> from + index, to - from + 1); } final int length = from - to; return ofGenerator(index -> to + (length - index), length + 1); } public static Seq rangeExclusive(final int from, final int to) { if (from == to) { return empty(); } if (from < to) { return ofGenerator(index -> from + index, to - from); } final int length = from - to; return ofGenerator(index -> to + (length - index), length); } }