javaslang.collection.Array Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javaslang Show documentation
Show all versions of javaslang Show documentation
Javaslang is a Java standard library extension built for Java 8 and above.
/* / \____ _ _ ____ ______ / \ ____ __ _______
* / / \/ \ / \/ \ / /\__\/ // \/ \ // /\__\ JΛVΛSLΛNG
* _/ / /\ \ \/ / /\ \\__\\ \ // /\ \ /\\/ \ /__\ \ Copyright 2014-2017 Javaslang, http://javaslang.io
* /___/\_/ \_/\____/\_/ \_/\__\/__/\__\_/ \_// \__/\_____/ Licensed under the Apache License, Version 2.0
*/
package javaslang.collection;
import javaslang.*;
import javaslang.collection.ArrayModule.Combinations;
import javaslang.control.Option;
import java.io.Serializable;
import java.util.*;
import java.util.HashSet;
import java.util.function.*;
import java.util.stream.Collector;
/**
* Array is a Traversable wrapper for {@code Object[]} containing elements of type {@code T}.
*
* @param Component type
* @author Ruslan Sennov, Daniel Dietrich
* @since 2.0.0
*/
public final class Array implements Kind1, T>, IndexedSeq, Serializable {
private static final long serialVersionUID = 1L;
private static final Array> EMPTY = new Array<>(new Object[0]);
private final Object[] back;
private Array(Object[] back) {
this.back = back;
}
/* package private */
static Array wrap(Object[] array) {
if (array.length == 0) {
return empty();
} else {
return new Array<>(array);
}
}
/**
* Returns a {@link java.util.stream.Collector} which may be used in conjunction with
* {@link java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a {@link javaslang.collection.Array}.
*
* @param Component type of the Vector.
* @return A {@link javaslang.collection.Array} Collector.
*/
public static Collector, Array> collector() {
final Supplier> supplier = ArrayList::new;
final BiConsumer, T> accumulator = ArrayList::add;
final BinaryOperator> combiner = (left, right) -> {
left.addAll(right);
return left;
};
final Function, Array> finisher = Array::ofAll;
return Collector.of(supplier, accumulator, combiner, finisher);
}
@SuppressWarnings("unchecked")
public static Array empty() {
return (Array) EMPTY;
}
/**
* Narrows a widened {@code Array extends T>} to {@code Array}
* by performing a type safe-cast. This is eligible because immutable/read-only
* collections are covariant.
*
* @param array An {@code Array}.
* @param Component type of the {@code Array}.
* @return the given {@code array} instance as narrowed type {@code Array}.
*/
@SuppressWarnings("unchecked")
public static Array narrow(Array extends T> array) {
return (Array) array;
}
/**
* Returns a singleton {@code Array}, i.e. a {@code Array} of one element.
*
* @param element An element.
* @param The component type
* @return A new Array instance containing the given element
*/
public static Array of(T element) {
return wrap(new Object[] { element });
}
/**
* Creates a Array of the given elements.
*
* @param Component type of the Array.
* @param elements Zero or more elements.
* @return A Array containing the given elements in the same order.
* @throws NullPointerException if {@code elements} is null
*/
@SuppressWarnings("varargs")
@SafeVarargs
public static Array of(T... elements) {
Objects.requireNonNull(elements, "elements is null");
return wrap(Arrays.copyOf(elements, elements.length));
}
/**
* Creates a Array of the given elements.
*
* The resulting Array has the same iteration order as the given iterable of elements
* if the iteration order of the elements is stable.
*
* @param Component type of the Array.
* @param elements An Iterable of elements.
* @return A Array containing the given elements in the same order.
* @throws NullPointerException if {@code elements} is null
*/
@SuppressWarnings("unchecked")
public static Array ofAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (elements instanceof Array) {
return (Array) elements;
} else {
return wrap(create(elements));
}
}
/**
* Creates a Array based on the elements of a boolean array.
*
* @param array a boolean array
* @return A new Array of Boolean values
*/
public static Array ofAll(boolean[] array) {
Objects.requireNonNull(array, "array is null");
return Array.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Array based on the elements of a byte array.
*
* @param array a byte array
* @return A new Array of Byte values
*/
public static Array ofAll(byte[] array) {
Objects.requireNonNull(array, "array is null");
return Array.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Array based on the elements of a char array.
*
* @param array a char array
* @return A new Array of Character values
*/
public static Array ofAll(char[] array) {
Objects.requireNonNull(array, "array is null");
return Array.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Array based on the elements of a double array.
*
* @param array a double array
* @return A new Array of Double values
*/
public static Array ofAll(double[] array) {
Objects.requireNonNull(array, "array is null");
return Array.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Array based on the elements of a float array.
*
* @param array a float array
* @return A new Array of Float values
*/
public static Array ofAll(float[] array) {
Objects.requireNonNull(array, "array is null");
return Array.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Array based on the elements of an int array.
*
* @param array an int array
* @return A new Array of Integer values
*/
public static Array ofAll(int[] array) {
Objects.requireNonNull(array, "array is null");
return Array.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Array based on the elements of a long array.
*
* @param array a long array
* @return A new Array of Long values
*/
public static Array ofAll(long[] array) {
Objects.requireNonNull(array, "array is null");
return Array.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Array based on the elements of a short array.
*
* @param array a short array
* @return A new Array of Short values
*/
public static Array ofAll(short[] array) {
Objects.requireNonNull(array, "array is null");
return Array.ofAll(Iterator.ofAll(array));
}
/**
* Returns an Array containing {@code n} values of a given Function {@code f}
* over a range of integer values from 0 to {@code n - 1}.
*
* @param Component type of the Array
* @param n The number of elements in the Array
* @param f The Function computing element values
* @return An Array consisting of elements {@code f(0),f(1), ..., f(n - 1)}
* @throws NullPointerException if {@code f} is null
*/
public static Array tabulate(int n, Function super Integer, ? extends T> f) {
Objects.requireNonNull(f, "f is null");
return Collections.tabulate(n, f, Array.empty(), Array::of);
}
/**
* Returns an Array containing {@code n} values supplied by a given Supplier {@code s}.
*
* @param Component type of the Array
* @param n The number of elements in the Array
* @param s The Supplier computing element values
* @return An Array of size {@code n}, where each element contains the result supplied by {@code s}.
* @throws NullPointerException if {@code s} is null
*/
public static Array fill(int n, Supplier extends T> s) {
Objects.requireNonNull(s, "s is null");
return Collections.fill(n, s, Array.empty(), Array::of);
}
public static Array range(char from, char toExclusive) {
return Array.ofAll(Iterator.range(from, toExclusive));
}
public static Array rangeBy(char from, char toExclusive, int step) {
return Array.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
public static Array rangeBy(double from, double toExclusive, double step) {
return Array.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
/**
* Creates a Array of int numbers starting from {@code from}, extending to {@code toExclusive - 1}.
*
* Examples:
*
*
* Array.range(0, 0) // = Array()
* Array.range(2, 0) // = Array()
* Array.range(-2, 2) // = Array(-2, -1, 0, 1)
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @return a range of int values as specified or the empty range if {@code from >= toExclusive}
*/
public static Array range(int from, int toExclusive) {
return Array.ofAll(Iterator.range(from, toExclusive));
}
/**
* Creates a Array of int numbers starting from {@code from}, extending to {@code toExclusive - 1},
* with {@code step}.
*
* Examples:
*
*
* Array.rangeBy(1, 3, 1) // = Array(1, 2)
* Array.rangeBy(1, 4, 2) // = Array(1, 3)
* Array.rangeBy(4, 1, -2) // = Array(4, 2)
* Array.rangeBy(4, 1, 2) // = Array()
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @param step the step
* @return a range of long values as specified or the empty range if
* {@code from >= toInclusive} and {@code step > 0} or
* {@code from <= toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
public static Array rangeBy(int from, int toExclusive, int step) {
return Array.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
/**
* Creates a Array of long numbers starting from {@code from}, extending to {@code toExclusive - 1}.
*
* Examples:
*
*
* Array.range(0L, 0L) // = Array()
* Array.range(2L, 0L) // = Array()
* Array.range(-2L, 2L) // = Array(-2L, -1L, 0L, 1L)
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @return a range of long values as specified or the empty range if {@code from >= toExclusive}
*/
public static Array range(long from, long toExclusive) {
return Array.ofAll(Iterator.range(from, toExclusive));
}
/**
* Creates a Array of long numbers starting from {@code from}, extending to {@code toExclusive - 1},
* with {@code step}.
*
* Examples:
*
*
* Array.rangeBy(1L, 3L, 1L) // = Array(1L, 2L)
* Array.rangeBy(1L, 4L, 2L) // = Array(1L, 3L)
* Array.rangeBy(4L, 1L, -2L) // = Array(4L, 2L)
* Array.rangeBy(4L, 1L, 2L) // = Array()
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @param step the step
* @return a range of long values as specified or the empty range if
* {@code from >= toInclusive} and {@code step > 0} or
* {@code from <= toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
public static Array rangeBy(long from, long toExclusive, long step) {
return Array.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
public static Array rangeClosed(char from, char toInclusive) {
return Array.ofAll(Iterator.rangeClosed(from, toInclusive));
}
public static Array rangeClosedBy(char from, char toInclusive, int step) {
return Array.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
public static Array rangeClosedBy(double from, double toInclusive, double step) {
return Array.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
/**
* Creates a Array of int numbers starting from {@code from}, extending to {@code toInclusive}.
*
* Examples:
*
*
* Array.rangeClosed(0, 0) // = Array(0)
* Array.rangeClosed(2, 0) // = Array()
* Array.rangeClosed(-2, 2) // = Array(-2, -1, 0, 1, 2)
*
*
*
* @param from the first number
* @param toInclusive the last number
* @return a range of int values as specified or the empty range if {@code from > toInclusive}
*/
public static Array rangeClosed(int from, int toInclusive) {
return Array.ofAll(Iterator.rangeClosed(from, toInclusive));
}
/**
* Creates a Array of int numbers starting from {@code from}, extending to {@code toInclusive},
* with {@code step}.
*
* Examples:
*
*
* Array.rangeClosedBy(1, 3, 1) // = Array(1, 2, 3)
* Array.rangeClosedBy(1, 4, 2) // = Array(1, 3)
* Array.rangeClosedBy(4, 1, -2) // = Array(4, 2)
* Array.rangeClosedBy(4, 1, 2) // = Array()
*
*
*
* @param from the first number
* @param toInclusive the last number
* @param step the step
* @return a range of int values as specified or the empty range if
* {@code from > toInclusive} and {@code step > 0} or
* {@code from < toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
public static Array rangeClosedBy(int from, int toInclusive, int step) {
return Array.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
/**
* Creates a Array of long numbers starting from {@code from}, extending to {@code toInclusive}.
*
* Examples:
*
*
* Array.rangeClosed(0L, 0L) // = Array(0L)
* Array.rangeClosed(2L, 0L) // = Array()
* Array.rangeClosed(-2L, 2L) // = Array(-2L, -1L, 0L, 1L, 2L)
*
*
*
* @param from the first number
* @param toInclusive the last number
* @return a range of long values as specified or the empty range if {@code from > toInclusive}
*/
public static Array rangeClosed(long from, long toInclusive) {
return Array.ofAll(Iterator.rangeClosed(from, toInclusive));
}
/**
* Creates a Array of long numbers starting from {@code from}, extending to {@code toInclusive},
* with {@code step}.
*
* Examples:
*
*
* Array.rangeClosedBy(1L, 3L, 1L) // = Array(1L, 2L, 3L)
* Array.rangeClosedBy(1L, 4L, 2L) // = Array(1L, 3L)
* Array.rangeClosedBy(4L, 1L, -2L) // = Array(4L, 2L)
* Array.rangeClosedBy(4L, 1L, 2L) // = Array()
*
*
*
* @param from the first number
* @param toInclusive the last number
* @param step the step
* @return a range of int values as specified or the empty range if
* {@code from > toInclusive} and {@code step > 0} or
* {@code from < toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
public static Array rangeClosedBy(long from, long toInclusive, long step) {
return Array.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
@Override
public Array append(T element) {
final Object[] arr = Arrays.copyOf(back, back.length + 1);
arr[back.length] = element;
return wrap(arr);
}
@Override
public Array appendAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
final Object[] source = create(elements);
if (source.length == 0) {
return this;
} else {
Object[] arr = Arrays.copyOf(back, back.length + source.length);
System.arraycopy(source, 0, arr, back.length, source.length);
return wrap(arr);
}
}
@Override
public boolean hasDefiniteSize() {
return true;
}
@Override
public boolean isTraversableAgain() {
return true;
}
@SuppressWarnings("unchecked")
@Override
public Iterator iterator() {
return new AbstractIterator() {
private int index = 0;
@Override
public boolean hasNext() {
return index < back.length;
}
@Override
public T getNext() {
return (T) back[index++];
}
};
}
@Override
public Array> combinations() {
return Array.rangeClosed(0, length()).map(this::combinations).flatMap(Function.identity());
}
@Override
public Array> combinations(int k) {
return Combinations.apply(this, Math.max(k, 0));
}
@Override
public Iterator> crossProduct(int power) {
return Collections.crossProduct(Array.empty(), this, power);
}
@SuppressWarnings("unchecked")
@Override
public T get(int index) {
if (index < 0 || index >= length()) {
throw new IndexOutOfBoundsException("get(" + index + ")");
}
return (T) back[index];
}
@Override
public Array distinct() {
return distinctBy(Function.identity());
}
@Override
public Array distinctBy(Comparator super T> comparator) {
Objects.requireNonNull(comparator, "comparator is null");
final java.util.Set seen = new java.util.TreeSet<>(comparator);
return filter(seen::add);
}
@Override
public Array distinctBy(Function super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor, "keyExtractor is null");
final java.util.Set seen = new java.util.HashSet<>();
return filter(t -> seen.add(keyExtractor.apply(t)));
}
@Override
public Array drop(long n) {
if (n <= 0) {
return this;
}
if (n >= length()) {
return empty();
}
final Object[] arr = new Object[back.length - (int) n];
System.arraycopy(back, (int) n, arr, 0, arr.length);
return wrap(arr);
}
@Override
public Array dropRight(long n) {
if (n <= 0) {
return this;
}
if (n >= length()) {
return empty();
}
return wrap(Arrays.copyOf(back, back.length - (int) n));
}
@Override
public Array dropUntil(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return dropWhile(predicate.negate());
}
@Override
public Array dropWhile(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
for (int i = 0; i < length(); i++) {
if (!predicate.test(get(i))) {
return drop(i);
}
}
return empty();
}
@Override
public Array filter(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
final java.util.List list = new ArrayList<>();
for (T t : this) {
if (predicate.test(t)) {
list.add(t);
}
}
if (list.size() == back.length) {
return this;
} else {
return list.isEmpty() ? empty() : wrap(list.toArray());
}
}
@Override
public Array flatMap(Function super T, ? extends Iterable extends U>> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
if (isEmpty()) {
return empty();
} else {
final java.util.List list = new ArrayList<>();
for (T t : this) {
for (U u : mapper.apply(t)) {
list.add(u);
}
}
return wrap(create(list));
}
}
@Override
public Map> groupBy(Function super T, ? extends C> classifier) {
return foldLeft(HashMap.empty(), (map, t) -> {
final C key = classifier.apply(t);
final Array values = map.get(key).map(ts -> ts.append(t)).getOrElse(Array.of(t));
return map.put(key, values);
});
}
@Override
public Iterator> grouped(long size) {
return sliding(size, size);
}
@SuppressWarnings("unchecked")
@Override
public T head() {
if (isEmpty()) {
throw new NoSuchElementException("head() on empty Array");
}
return (T) back[0];
}
@Override
public int indexOf(T element, int from) {
for (int i = from; i < length(); i++) {
if (Objects.equals(get(i), element)) {
return i;
}
}
return -1;
}
@Override
public Array init() {
if (isEmpty()) {
throw new UnsupportedOperationException("init of empty Array");
}
final Object[] arr = new Object[length() - 1];
System.arraycopy(back, 0, arr, 0, arr.length);
return wrap(arr);
}
@Override
public Option> initOption() {
return isEmpty() ? Option.none() : Option.some(init());
}
@Override
public boolean isEmpty() {
return back.length == 0;
}
private Object readResolve() {
if (isEmpty()) {
return EMPTY;
} else {
return this;
}
}
@Override
public Array insert(int index, T element) {
if (index < 0 || index > length()) {
throw new IndexOutOfBoundsException("insert(" + index + ", e) on Array of length " + length());
}
final Object[] arr = new Object[back.length + 1];
System.arraycopy(back, 0, arr, 0, index);
arr[index] = element;
System.arraycopy(back, index, arr, index + 1, back.length - index);
return wrap(arr);
}
@Override
public Array insertAll(int index, Iterable extends T> elements) {
if (index < 0) {
throw new IndexOutOfBoundsException("insert(" + index + ", e)");
}
if (index > length()) {
throw new IndexOutOfBoundsException("insert(" + index + ", e) on Vector of length " + length());
}
final Object[] list = create(elements);
if (list.length == 0) {
return this;
} else {
Object[] arr = new Object[back.length + list.length];
System.arraycopy(back, 0, arr, 0, index);
System.arraycopy(list, 0, arr, index, list.length);
System.arraycopy(back, index, arr, index + list.length, back.length - index);
return wrap(arr);
}
}
@Override
public Array intersperse(T element) {
if (back.length <= 1) {
return this;
} else {
final Object[] arr = new Object[back.length * 2 - 1];
for (int i = 0; i < back.length; i++) {
arr[i * 2] = back[i];
if (i > 0) {
arr[i * 2 - 1] = element;
}
}
return wrap(arr);
}
}
@Override
public int lastIndexOf(T element, int end) {
for (int i = Math.min(end, length() - 1); i >= 0; i--) {
if (Objects.equals(get(i), element)) {
return i;
}
}
return -1;
}
@Override
public int length() {
return back.length;
}
@Override
public Array map(Function super T, ? extends U> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
final Object[] arr = new Object[length()];
for (int i = 0; i < back.length; i++) {
arr[i] = mapper.apply(get(i));
}
return wrap(arr);
}
@Override
public Array padTo(int length, T element) {
if (length <= length()) {
return this;
} else {
return appendAll(Iterator.continually(element).take(length - length()));
}
}
@Override
public Array patch(int from, Iterable extends T> that, int replaced) {
from = from < 0 ? 0 : from;
replaced = replaced < 0 ? 0 : replaced;
Array result = take(from).appendAll(that);
from += replaced;
result = result.appendAll(drop(from));
return result;
}
@Override
public Tuple2, Array> partition(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
final java.util.List left = new ArrayList<>(), right = new ArrayList<>();
for (T t : this) {
(predicate.test(t) ? left : right).add(t);
}
return Tuple.of(Array.ofAll(left), Array.ofAll(right));
}
@Override
public Array peek(Consumer super T> action) {
Objects.requireNonNull(action, "action is null");
if (!isEmpty()) {
action.accept(head());
}
return this;
}
@Override
public Array> permutations() {
if (isEmpty()) {
return empty();
} else {
final Array tail = tail();
if (tail.isEmpty()) {
return Array.of(this);
} else {
final Array> zero = empty();
return distinct().foldLeft(zero, (xs, x) -> {
final Function, Array> prepend = l -> l.prepend(x);
return xs.appendAll(remove(x).permutations().map(prepend));
});
}
}
}
@Override
public Array prepend(T element) {
return insert(0, element);
}
@Override
public Array prependAll(Iterable extends T> elements) {
return insertAll(0, elements);
}
@Override
public Array remove(T element) {
int found = -1;
for (int i = 0; i < length(); i++) {
final T value = get(i);
if (element.equals(value)) {
found = i;
break;
}
}
if (found < 0) {
return this;
} else {
return removeAt(found);
}
}
@Override
public Array removeFirst(Predicate predicate) {
Objects.requireNonNull(predicate, "predicate is null");
int found = -1;
for (int i = 0; i < length(); i++) {
final T value = get(i);
if (predicate.test(value)) {
found = i;
break;
}
}
if (found < 0) {
return this;
} else {
return removeAt(found);
}
}
@Override
public Array removeLast(Predicate predicate) {
Objects.requireNonNull(predicate, "predicate is null");
int found = -1;
for (int i = length() - 1; i >= 0; i--) {
final T value = get(i);
if (predicate.test(value)) {
found = i;
break;
}
}
if (found < 0) {
return this;
} else {
return removeAt(found);
}
}
@Override
public Array removeAt(int index) {
if (index < 0) {
throw new IndexOutOfBoundsException("removeAt(" + index + ")");
}
if (index >= length()) {
throw new IndexOutOfBoundsException("removeAt(" + index + ")");
}
final Object[] arr = new Object[length() - 1];
System.arraycopy(back, 0, arr, 0, index);
System.arraycopy(back, index + 1, arr, index, length() - index - 1);
return wrap(arr);
}
@Override
public Array removeAll(T element) {
final java.util.List list = new ArrayList<>();
for (int i = 0; i < length(); i++) {
T value = get(i);
if (!element.equals(value)) {
list.add(value);
}
}
if (list.size() == length()) {
return this;
} else {
return wrap(list.toArray());
}
}
@Override
public Array removeAll(Iterable extends T> elements) {
final java.util.Set removed = new HashSet<>();
for (T element : elements) {
removed.add(element);
}
final java.util.List list = new ArrayList<>();
for (int i = 0; i < length(); i++) {
T value = get(i);
if (!removed.contains(value)) {
list.add(value);
}
}
if (list.size() == length()) {
return this;
} else {
return wrap(list.toArray());
}
}
@Override
public Array replace(T currentElement, T newElement) {
final Object[] arr = new Object[length()];
boolean found = false;
for (int i = 0; i < length(); i++) {
final T value = get(i);
if (found) {
arr[i] = back[i];
} else {
if (currentElement.equals(value)) {
arr[i] = newElement;
found = true;
} else {
arr[i] = back[i];
}
}
}
return found ? wrap(arr) : this;
}
@Override
public Array replaceAll(T currentElement, T newElement) {
final Object[] arr = new Object[length()];
boolean changed = false;
for (int i = 0; i < length(); i++) {
final T value = get(i);
if (currentElement.equals(value)) {
arr[i] = newElement;
changed = true;
} else {
arr[i] = back[i];
}
}
return changed ? wrap(arr) : this;
}
@Override
public Array retainAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
final java.util.Set kept = new HashSet<>();
for (T element : elements) {
kept.add(element);
}
final java.util.List list = new ArrayList<>();
for (int i = 0; i < length(); i++) {
T value = get(i);
if (kept.contains(value)) {
list.add(value);
}
}
if (list.size() == length()) {
return this;
} else {
return wrap(list.toArray());
}
}
@Override
public Array reverse() {
final Object[] arr = new Object[back.length];
for (int i = 0; i < back.length; i++) {
arr[back.length - 1 - i] = back[i];
}
return wrap(arr);
}
@Override
public Array scan(T zero, BiFunction super T, ? super T, ? extends T> operation) {
return scanLeft(zero, operation);
}
@Override
public Array scanLeft(U zero, BiFunction super U, ? super T, ? extends U> operation) {
Objects.requireNonNull(operation, "operation is null");
return Collections.scanLeft(this, zero, operation,
new java.util.ArrayList<>(), (c, u) -> {
c.add(u);
return c;
}, list -> Array.wrap(list.toArray()));
}
@Override
public Array scanRight(U zero, BiFunction super T, ? super U, ? extends U> operation) {
Objects.requireNonNull(operation, "operation is null");
return Collections.scanRight(this, zero, operation, List.empty(), List::prepend, list -> Array.wrap(list.toJavaArray()));
}
@Override
public Array slice(long beginIndex, long endIndex) {
if (beginIndex >= endIndex || beginIndex >= length() || isEmpty()) {
return Array.empty();
}
if (beginIndex <= 0 && endIndex >= length()) {
return this;
}
final long index = Math.max(beginIndex, 0);
final long length = Math.min(endIndex, length()) - index;
final Object[] arr = new Object[(int) length];
System.arraycopy(back, (int) index, arr, 0, (int) length);
return wrap(arr);
}
@Override
public Iterator> sliding(long size) {
return sliding(size, 1);
}
@Override
public Iterator> sliding(long size, long step) {
return iterator().sliding(size, step).map(Array::ofAll);
}
@Override
public Array sorted() {
final Object[] arr = Arrays.copyOf(back, back.length);
Arrays.sort(arr);
return wrap(arr);
}
@SuppressWarnings("unchecked")
@Override
public Array sorted(Comparator super T> comparator) {
final Object[] arr = Arrays.copyOf(back, back.length);
Arrays.sort(arr, (o1, o2) -> comparator.compare((T) o1, (T) o2));
return wrap(arr);
}
@Override
public > Array sortBy(Function super T, ? extends U> mapper) {
return sortBy(U::compareTo, mapper);
}
@Override
public Array sortBy(Comparator super U> comparator, Function super T, ? extends U> mapper) {
final Function super T, ? extends U> domain = Function1.of(mapper::apply).memoized();
return toJavaStream()
.sorted((e1, e2) -> comparator.compare(domain.apply(e1), domain.apply(e2)))
.collect(collector());
}
@Override
public Tuple2, Array> splitAt(long n) {
return Tuple.of(take(n), drop(n));
}
@Override
public Tuple2, Array> splitAt(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
final Array init = takeWhile(predicate.negate());
return Tuple.of(init, drop(init.length()));
}
@Override
public Tuple2, Array> splitAtInclusive(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
for (int i = 0; i < back.length; i++) {
final T value = get(i);
if (predicate.test(value)) {
if (i == back.length - 1) {
return Tuple.of(this, empty());
} else {
return Tuple.of(take(i + 1), drop(i + 1));
}
}
}
return Tuple.of(this, empty());
}
@Override
public Spliterator spliterator() {
return Spliterators.spliterator(iterator(), length(), Spliterator.ORDERED | Spliterator.IMMUTABLE);
}
@Override
public Tuple2, Array> span(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return Tuple.of(takeWhile(predicate), dropWhile(predicate));
}
@Override
public Array subSequence(int beginIndex) {
if (beginIndex < 0) {
throw new IndexOutOfBoundsException("subSequence(" + beginIndex + ")");
}
if (beginIndex > length()) {
throw new IndexOutOfBoundsException("subSequence(" + beginIndex + ")");
}
return drop(beginIndex);
}
@Override
public Array subSequence(int beginIndex, int endIndex) {
if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
throw new IndexOutOfBoundsException(
String.format("subSequence(%s, %s) on List of length %s", beginIndex, endIndex, length()));
}
if (beginIndex == endIndex) {
return Array.empty();
}
final Object[] arr = new Object[endIndex - beginIndex];
System.arraycopy(back, beginIndex, arr, 0, arr.length);
return wrap(arr);
}
@Override
public Array tail() {
if (isEmpty()) {
throw new UnsupportedOperationException("tail() on empty Array");
}
final Object[] arr = new Object[back.length - 1];
System.arraycopy(back, 1, arr, 0, arr.length);
return wrap(arr);
}
@Override
public Option> tailOption() {
return isEmpty() ? Option.none() : Option.some(tail());
}
@Override
public Array take(long n) {
if (n >= length()) {
return this;
}
if (n <= 0) {
return empty();
}
return wrap(Arrays.copyOf(back, (int) n));
}
@Override
public Array takeRight(long n) {
if (n >= length()) {
return this;
}
if (n <= 0) {
return empty();
}
final Object[] arr = new Object[(int) n];
System.arraycopy(back, back.length - (int) n, arr, 0, (int) n);
return wrap(arr);
}
@Override
public Array takeUntil(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return takeWhile(predicate.negate());
}
@Override
public Array takeWhile(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
for (int i = 0; i < back.length; i++) {
final T value = get(i);
if (!predicate.test(value)) {
return take(i);
}
}
return this;
}
/**
* Transforms this {@code Array}.
*
* @param f A transformation
* @param Type of transformation result
* @return An instance of type {@code U}
* @throws NullPointerException if {@code f} is null
*/
public U transform(Function super Array, ? extends U> f) {
Objects.requireNonNull(f, "f is null");
return f.apply(this);
}
@Override
public Array unit(Iterable extends U> iterable) {
return Array.ofAll(iterable);
}
@Override
public Tuple2, Array> unzip(
Function super T, Tuple2 extends T1, ? extends T2>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
if (isEmpty()) {
return Tuple.of(empty(), empty());
} else {
final Object[] xs = new Object[back.length];
final Object[] ys = new Object[back.length];
for (int i = 0; i < back.length; i++) {
final Tuple2 extends T1, ? extends T2> t = unzipper.apply(get(i));
xs[i] = t._1;
ys[i] = t._2;
}
return Tuple.of(wrap(xs), wrap(ys));
}
}
@Override
public Tuple3, Array, Array> unzip3(Function super T, Tuple3 extends T1, ? extends T2, ? extends T3>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
if (isEmpty()) {
return Tuple.of(empty(), empty(), empty());
} else {
final Object[] xs = new Object[back.length];
final Object[] ys = new Object[back.length];
final Object[] zs = new Object[back.length];
for (int i = 0; i < back.length; i++) {
final Tuple3 extends T1, ? extends T2, ? extends T3> t = unzipper.apply(get(i));
xs[i] = t._1;
ys[i] = t._2;
zs[i] = t._3;
}
return Tuple.of(wrap(xs), wrap(ys), wrap(zs));
}
}
@Override
public Array update(int index, T element) {
if (index < 0) {
throw new IndexOutOfBoundsException("update(" + index + ")");
}
if (index >= length()) {
throw new IndexOutOfBoundsException("update(" + index + ")");
}
final Object[] arr = create(this);
arr[index] = element;
return wrap(arr);
}
@Override
public Array> zip(Iterable extends U> that) {
Objects.requireNonNull(that, "that is null");
return Array.ofAll(iterator().zip(that));
}
@Override
public Array> zipAll(Iterable extends U> that, T thisElem, U thatElem) {
Objects.requireNonNull(that, "that is null");
return Array.ofAll(iterator().zipAll(that, thisElem, thatElem));
}
@Override
public Array> zipWithIndex() {
return Array.ofAll(iterator().zipWithIndex());
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof Array) {
final Object[] arr1 = back;
final Object[] arr2 = ((Array>) o).back;
return Objects.deepEquals(arr1, arr2);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hash(back);
}
@Override
public String stringPrefix() {
return "Array";
}
@Override
public String toString() {
return mkString(stringPrefix() + "(", ", ", ")");
}
private static Object[] create(Iterable elements) {
if (elements instanceof java.util.List) {
final java.util.List list = (java.util.List) elements;
return list.toArray();
} else {
final java.util.Iterator extends T> it = elements.iterator();
final java.util.List list = new java.util.ArrayList<>();
while (it.hasNext()) {
list.add(it.next());
}
return list.toArray();
}
}
}
interface ArrayModule {
final class Combinations {
static Array> apply(Array elements, int k) {
if (k == 0) {
return Array.of(Array.empty());
} else {
return elements.zipWithIndex().flatMap(
t -> apply(elements.drop(t._2 + 1), (k - 1)).map(c -> c.prepend(t._1))
);
}
}
}
}