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

javaslang.collection.Vector Maven / Gradle / Ivy

There is a newer version: 0.2.5
Show newest version
/*     / \____  _    _  ____   ______  / \ ____  __    _______
 *    /  /    \/ \  / \/    \ /  /\__\/  //    \/  \  //  /\__\   JΛVΛSLΛNG
 *  _/  /  /\  \  \/  /  /\  \\__\\  \  //  /\  \ /\\/ \ /__\ \   Copyright 2014-2016 Javaslang, http://javaslang.io
 * /___/\_/  \_/\____/\_/  \_/\__\/__/\__\_/  \_//  \__/\_____/   Licensed under the Apache License, Version 2.0
 */
package javaslang.collection;

import javaslang.*;
import javaslang.collection.VectorModule.Combinations;
import javaslang.control.Option;

import java.io.Serializable;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;

/**
 * Vector is the default Seq implementation. It provides the best performance in between Array (with constant time element access)
 * and List (with constant time element addition).
 *
 * @param  Component type of the Vector.
 * @author Ruslan Sennov
 * @since 2.0.0
 */
public final class Vector implements Kind1, T>, IndexedSeq, Serializable {

    private static final long serialVersionUID = 1L;

    private static final Vector EMPTY = new Vector<>(HashArrayMappedTrie.empty());

    private final HashArrayMappedTrie trie;
    private final int indexShift;

    private Vector(HashArrayMappedTrie trie) {
        this(0, trie);
    }

    private Vector(int indexShift, HashArrayMappedTrie trie) {
        this.trie = trie;
        this.indexShift = indexShift;
    }

    /**
     * Returns the empty Vector.
     *
     * @param  Component type.
     * @return The empty Vector.
     */
    @SuppressWarnings("unchecked")
    public static  Vector empty() {
        return (Vector) EMPTY;
    }

    /**
     * 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.Vector}.
     *
     * @param  Component type of the Vector.
     * @return A javaslang.collection.List Collector.
     */
    public static  Collector, Vector> collector() {
        final Supplier> supplier = ArrayList::new;
        final BiConsumer, T> accumulator = ArrayList::add;
        final BinaryOperator> combiner = (left, right) -> {
            left.addAll(right);
            return left;
        };
        final Function, Vector> finisher = Vector::ofAll;
        return Collector.of(supplier, accumulator, combiner, finisher);
    }

    /**
     * Narrows a widened {@code Vector} to {@code Vector}
     * by performing a type safe-cast. This is eligible because immutable/read-only
     * collections are covariant.
     *
     * @param vector An {@code Vector}.
     * @param     Component type of the {@code Vector}.
     * @return the given {@code vector} instance as narrowed type {@code Vector}.
     */
    @SuppressWarnings("unchecked")
    public static  Vector narrow(Vector vector) {
        return (Vector) vector;
    }

    /**
     * Returns a singleton {@code Vector}, i.e. a {@code Vector} of one element.
     *
     * @param element An element.
     * @param      The component type
     * @return A new Vector instance containing the given element
     */
    public static  Vector of(T element) {
        return new Vector<>(HashArrayMappedTrie. empty().put(0, element));
    }

    /**
     * Creates a Vector of the given elements.
     *
     * @param       Component type of the Vector.
     * @param elements Zero or more elements.
     * @return A vector containing the given elements in the same order.
     * @throws NullPointerException if {@code elements} is null
     */
    @SafeVarargs
    public static  Vector of(T... elements) {
        Objects.requireNonNull(elements, "elements is null");
        HashArrayMappedTrie result = HashArrayMappedTrie.empty();
        for (T element : elements) {
            result = result.put(result.size(), element);
        }
        return wrap(result);
    }

    /**
     * Returns a Vector 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 Vector
     * @param n   The number of elements in the Vector
     * @param f   The Function computing element values
     * @return A Vector consisting of elements {@code f(0),f(1), ..., f(n - 1)}
     * @throws NullPointerException if {@code f} is null
     */
    public static  Vector tabulate(int n, Function f) {
        Objects.requireNonNull(f, "f is null");
        return Collections.tabulate(n, f, Vector.empty(), Vector::of);
    }

    /**
     * Returns a Vector containing {@code n} values supplied by a given Supplier {@code s}.
     *
     * @param  Component type of the Vector
     * @param n   The number of elements in the Vector
     * @param s   The Supplier computing element values
     * @return A Vector of size {@code n}, where each element contains the result supplied by {@code s}.
     * @throws NullPointerException if {@code s} is null
     */
    public static  Vector fill(int n, Supplier s) {
        Objects.requireNonNull(s, "s is null");
        return Collections.fill(n, s, Vector.empty(), Vector::of);
    }

    /**
     * Creates a Vector of the given elements.
     *
     * The resulting vector 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 Vector.
     * @param elements An Iterable of elements.
     * @return A vector containing the given elements in the same order.
     * @throws NullPointerException if {@code elements} is null
     */
    @SuppressWarnings("unchecked")
    public static  Vector ofAll(Iterable elements) {
        Objects.requireNonNull(elements, "elements is null");
        if (elements instanceof Vector) {
            return (Vector) elements;
        } else {
            HashArrayMappedTrie trie = HashArrayMappedTrie.empty();
            for (T element : elements) {
                trie = trie.put(trie.size(), element);
            }
            return wrap(trie);
        }
    }

    /**
     * Creates a Vector based on the elements of a boolean array.
     *
     * @param array a boolean array
     * @return A new Vector of Boolean values
     */
    public static Vector ofAll(boolean[] array) {
        Objects.requireNonNull(array, "array is null");
        return Vector.ofAll(Iterator.ofAll(array));
    }

    /**
     * Creates a Vector based on the elements of a byte array.
     *
     * @param array a byte array
     * @return A new Vector of Byte values
     */
    public static Vector ofAll(byte[] array) {
        Objects.requireNonNull(array, "array is null");
        return Vector.ofAll(Iterator.ofAll(array));
    }

    /**
     * Creates a Vector based on the elements of a char array.
     *
     * @param array a char array
     * @return A new Vector of Character values
     */
    public static Vector ofAll(char[] array) {
        Objects.requireNonNull(array, "array is null");
        return Vector.ofAll(Iterator.ofAll(array));
    }

    /**
     * Creates a Vector based on the elements of a double array.
     *
     * @param array a double array
     * @return A new Vector of Double values
     */
    public static Vector ofAll(double[] array) {
        Objects.requireNonNull(array, "array is null");
        return Vector.ofAll(Iterator.ofAll(array));
    }

    /**
     * Creates a Vector based on the elements of a float array.
     *
     * @param array a float array
     * @return A new Vector of Float values
     */
    public static Vector ofAll(float[] array) {
        Objects.requireNonNull(array, "array is null");
        return Vector.ofAll(Iterator.ofAll(array));
    }

    /**
     * Creates a Vector based on the elements of an int array.
     *
     * @param array an int array
     * @return A new Vector of Integer values
     */
    public static Vector ofAll(int[] array) {
        Objects.requireNonNull(array, "array is null");
        return Vector.ofAll(Iterator.ofAll(array));
    }

    /**
     * Creates a Vector based on the elements of a long array.
     *
     * @param array a long array
     * @return A new Vector of Long values
     */
    public static Vector ofAll(long[] array) {
        Objects.requireNonNull(array, "array is null");
        return Vector.ofAll(Iterator.ofAll(array));
    }

    /**
     * Creates a Vector based on the elements of a short array.
     *
     * @param array a short array
     * @return A new Vector of Short values
     */
    public static Vector ofAll(short[] array) {
        Objects.requireNonNull(array, "array is null");
        return Vector.ofAll(Iterator.ofAll(array));
    }

    public static Vector range(char from, char toExclusive) {
        return Vector.ofAll(Iterator.range(from, toExclusive));
    }

    public static Vector rangeBy(char from, char toExclusive, int step) {
        return Vector.ofAll(Iterator.rangeBy(from, toExclusive, step));
    }

    public static Vector rangeBy(double from, double toExclusive, double step) {
        return Vector.ofAll(Iterator.rangeBy(from, toExclusive, step));
    }

    /**
     * Creates a Vector of int numbers starting from {@code from}, extending to {@code toExclusive - 1}.
     * 

* Examples: *

     * 
     * Vector.range(0, 0)  // = Vector()
     * Vector.range(2, 0)  // = Vector()
     * Vector.range(-2, 2) // = Vector(-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 Vector range(int from, int toExclusive) { return Vector.ofAll(Iterator.range(from, toExclusive)); } /** * Creates a Vector of int numbers starting from {@code from}, extending to {@code toExclusive - 1}, * with {@code step}. *

* Examples: *

     * 
     * Vector.rangeBy(1, 3, 1)  // = Vector(1, 2)
     * Vector.rangeBy(1, 4, 2)  // = Vector(1, 3)
     * Vector.rangeBy(4, 1, -2) // = Vector(4, 2)
     * Vector.rangeBy(4, 1, 2)  // = Vector()
     * 
     * 
* * @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 Vector rangeBy(int from, int toExclusive, int step) { return Vector.ofAll(Iterator.rangeBy(from, toExclusive, step)); } /** * Creates a Vector of long numbers starting from {@code from}, extending to {@code toExclusive - 1}. *

* Examples: *

     * 
     * Vector.range(0L, 0L)  // = Vector()
     * Vector.range(2L, 0L)  // = Vector()
     * Vector.range(-2L, 2L) // = Vector(-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 Vector range(long from, long toExclusive) { return Vector.ofAll(Iterator.range(from, toExclusive)); } /** * Creates a Vector of long numbers starting from {@code from}, extending to {@code toExclusive - 1}, * with {@code step}. *

* Examples: *

     * 
     * Vector.rangeBy(1L, 3L, 1L)  // = Vector(1L, 2L)
     * Vector.rangeBy(1L, 4L, 2L)  // = Vector(1L, 3L)
     * Vector.rangeBy(4L, 1L, -2L) // = Vector(4L, 2L)
     * Vector.rangeBy(4L, 1L, 2L)  // = Vector()
     * 
     * 
* * @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 Vector rangeBy(long from, long toExclusive, long step) { return Vector.ofAll(Iterator.rangeBy(from, toExclusive, step)); } public static Vector rangeClosed(char from, char toInclusive) { return Vector.ofAll(Iterator.rangeClosed(from, toInclusive)); } public static Vector rangeClosedBy(char from, char toInclusive, int step) { return Vector.ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } public static Vector rangeClosedBy(double from, double toInclusive, double step) { return Vector.ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } /** * Creates a Vector of int numbers starting from {@code from}, extending to {@code toInclusive}. *

* Examples: *

     * 
     * Vector.rangeClosed(0, 0)  // = Vector(0)
     * Vector.rangeClosed(2, 0)  // = Vector()
     * Vector.rangeClosed(-2, 2) // = Vector(-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 Vector rangeClosed(int from, int toInclusive) { return Vector.ofAll(Iterator.rangeClosed(from, toInclusive)); } /** * Creates a Vector of int numbers starting from {@code from}, extending to {@code toInclusive}, * with {@code step}. *

* Examples: *

     * 
     * Vector.rangeClosedBy(1, 3, 1)  // = Vector(1, 2, 3)
     * Vector.rangeClosedBy(1, 4, 2)  // = Vector(1, 3)
     * Vector.rangeClosedBy(4, 1, -2) // = Vector(4, 2)
     * Vector.rangeClosedBy(4, 1, 2)  // = Vector()
     * 
     * 
* * @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 Vector rangeClosedBy(int from, int toInclusive, int step) { return Vector.ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } /** * Creates a Vector of long numbers starting from {@code from}, extending to {@code toInclusive}. *

* Examples: *

     * 
     * Vector.rangeClosed(0L, 0L)  // = Vector(0L)
     * Vector.rangeClosed(2L, 0L)  // = Vector()
     * Vector.rangeClosed(-2L, 2L) // = Vector(-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 Vector rangeClosed(long from, long toInclusive) { return Vector.ofAll(Iterator.rangeClosed(from, toInclusive)); } /** * Creates a Vector of long numbers starting from {@code from}, extending to {@code toInclusive}, * with {@code step}. *

* Examples: *

     * 
     * Vector.rangeClosedBy(1L, 3L, 1L)  // = Vector(1L, 2L, 3L)
     * Vector.rangeClosedBy(1L, 4L, 2L)  // = Vector(1L, 3L)
     * Vector.rangeClosedBy(4L, 1L, -2L) // = Vector(4L, 2L)
     * Vector.rangeClosedBy(4L, 1L, 2L)  // = Vector()
     * 
     * 
* * @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 Vector rangeClosedBy(long from, long toInclusive, long step) { return Vector.ofAll(Iterator.rangeClosedBy(from, toInclusive, step)); } @Override public Vector append(T element) { return new Vector<>(indexShift, trie.put(length() + indexShift, element)); } @Override public Vector appendAll(Iterable elements) { HashArrayMappedTrie result = trie; for (T element : elements) { result = result.put(result.size() + indexShift, element); } return new Vector<>(indexShift, result); } @Override public Vector> combinations() { return Vector.rangeClosed(0, length()).map(this::combinations).flatMap(Function.identity()); } @Override public Vector> combinations(int k) { return Combinations.apply(this, Math.max(k, 0)); } @Override public Iterator> crossProduct(int power) { return Collections.crossProduct(Vector.empty(), this, power); } @Override public Vector distinct() { return distinctBy(Function.identity()); } @Override public Vector distinctBy(Comparator comparator) { Objects.requireNonNull(comparator, "comparator is null"); final java.util.Set seen = new java.util.TreeSet<>(comparator); return filter(seen::add); } @Override public Vector distinctBy(Function 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 Vector drop(long n) { if (n <= 0) { return this; } if (n >= length()) { return empty(); } HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = (int) n; i < length(); i++) { trie = trie.put(i - (int) n, get(i)); } return wrap(trie); } @Override public Vector dropRight(long n) { if (n <= 0) { return this; } if (n >= length()) { return empty(); } HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i < length() - n; i++) { trie = trie.put(trie.size(), get(i)); } return wrap(trie); } @Override public Vector dropUntil(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); return dropWhile(predicate.negate()); } @Override public Vector dropWhile(Predicate 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 Vector filter(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (T t : this) { if (predicate.test(t)) { trie = trie.put(trie.size(), t); } } if (trie.size() == length()) { return this; } else { return wrap(trie); } } @Override public Vector flatMap(Function> mapper) { Objects.requireNonNull(mapper, "mapper is null"); if (isEmpty()) { return empty(); } else { HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i < length(); i++) { for (U u : mapper.apply(get(i))) { trie = trie.put(trie.size(), u); } } return wrap(trie); } } @Override public T get(int index) { if (index < 0 || index >= length()) { throw new IndexOutOfBoundsException("get(" + index + ")"); } return trie.get(index + indexShift).get(); } @Override public T head() { if (isEmpty()) { throw new NoSuchElementException("head of empty vector"); } else { return get(0); } } @Override public Map> groupBy(Function classifier) { Objects.requireNonNull(classifier, "classifier is null"); return iterator().groupBy(classifier).map((c, it) -> Tuple.of(c, Vector.ofAll(it))); } @Override public Iterator> grouped(long size) { return sliding(size, size); } @Override public boolean hasDefiniteSize() { return true; } @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 Vector init() { if (isEmpty()) { throw new UnsupportedOperationException("init of empty vector"); } return new Vector<>(indexShift, trie.remove(length() + indexShift - 1)); } @Override public Option> initOption() { return isEmpty() ? Option.none() : Option.some(init()); } @Override public Vector insert(int index, T element) { if (index < 0) { throw new IndexOutOfBoundsException("insert(" + index + ", e)"); } if (index > length()) { throw new IndexOutOfBoundsException("insert(" + index + ", e) on Vector of length " + length()); } HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i <= length(); i++) { if (i == index) { trie = trie.put(trie.size(), element); } if (i < length()) { trie = trie.put(trie.size(), get(i)); } } return new Vector<>(trie); } @Override public Vector insertAll(int index, Iterable elements) { if (index < 0) { throw new IndexOutOfBoundsException("insert(" + index + ", e)"); } if (index > length()) { throw new IndexOutOfBoundsException("insert(" + index + ", e) on Vector of length " + length()); } HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i <= length(); i++) { if (i == index) { for (T element : elements) { trie = trie.put(trie.size(), element); } } if (i < length()) { trie = trie.put(trie.size(), get(i)); } } return new Vector<>(trie); } @Override public Vector intersperse(T element) { HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i < length(); i++) { if (i > 0) { trie = trie.put(trie.size(), element); } trie = trie.put(trie.size(), get(i)); } return wrap(trie); } @Override public boolean isEmpty() { return trie.isEmpty(); } @Override public boolean isTraversableAgain() { return true; } @Override public Iterator iterator() { return new AbstractIterator() { private int index = indexShift; private final int size = trie.size() + indexShift; @Override public boolean hasNext() { return index < size; } @Override public T getNext() { return trie.get(index++).get(); } }; } @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 trie.size(); } @Override public Vector map(Function mapper) { Objects.requireNonNull(mapper, "mapper is null"); HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i < length(); i++) { trie = trie.put(i, mapper.apply(get(i))); } return wrap(trie); } @Override public Vector padTo(int length, T element) { if (length <= length()) { return this; } else { return appendAll(Iterator.continually(element).take(length - length())); } } @Override public Vector patch(int from, Iterable that, int replaced) { from = from < 0 ? 0 : from; replaced = replaced < 0 ? 0 : replaced; Vector result = take(from).appendAll(that); from += replaced; result = result.appendAll(drop(from)); return result; } @Override public Tuple2, Vector> partition(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); final java.util.List left = new ArrayList<>(), right = new ArrayList<>(); for (int i = 0; i < length(); i++) { T t = get(i); (predicate.test(t) ? left : right).add(t); } return Tuple.of(Vector.ofAll(left), Vector.ofAll(right)); } @Override public Vector peek(Consumer action) { Objects.requireNonNull(action, "action is null"); if (!isEmpty()) { action.accept(head()); } return this; } @Override public Vector> permutations() { if (isEmpty()) { return Vector.empty(); } else { final Vector tail = tail(); if (tail.isEmpty()) { return Vector.of(this); } else { final Vector> zero = empty(); return distinct().foldLeft(zero, (xs, x) -> { final Function, Vector> prepend = l -> l.prepend(x); return xs.appendAll(remove(x).permutations().map(prepend)); }); } } } @Override public Vector prepend(T element) { final int newIndexShift = indexShift - 1; return new Vector<>(newIndexShift, trie.put(newIndexShift, element)); } @Override public Vector prependAll(Iterable elements) { List list = List.ofAll(elements); final int newIndexShift = indexShift - list.length(); HashArrayMappedTrie newTrie = trie; for (int i = newIndexShift; !list.isEmpty(); i++) { newTrie = newTrie.put(i, list.head()); list = list.tail(); } return new Vector<>(newIndexShift, newTrie); } @Override public Vector remove(T element) { HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); boolean found = false; for (int i = 0; i < length(); i++) { final T value = get(i); if (found) { trie = trie.put(trie.size(), value); } else { if (element.equals(value)) { found = true; } else { trie = trie.put(trie.size(), value); } } } return trie.size() == length() ? this : wrap(trie); } @Override public Vector removeFirst(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); boolean found = false; for (int i = 0; i < length(); i++) { final T value = get(i); if (found) { trie = trie.put(trie.size(), value); } else { if (predicate.test(value)) { found = true; } else { trie = trie.put(trie.size(), value); } } } return trie.size() == length() ? this : wrap(trie); } @Override public Vector removeLast(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); for (int i = length() - 1; i >= 0; i--) { if (predicate.test(get(i))) { return removeAt(i); } } return this; } @Override public Vector removeAt(int index) { if (index < 0) { throw new IndexOutOfBoundsException("removeAt(" + index + ")"); } if (index >= length()) { throw new IndexOutOfBoundsException("removeAt(" + index + ")"); } HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i < length(); i++) { if (i != index) { trie = trie.put(trie.size(), get(i)); } } return wrap(trie); } @Override public Vector removeAll(T element) { HashArrayMappedTrie result = HashArrayMappedTrie.empty(); for (int i = 0; i < length(); i++) { final T value = get(i); if (!element.equals(value)) { result = result.put(result.size(), value); } } return result.size() == length() ? this : wrap(result); } @Override public Vector removeAll(Iterable elements) { Objects.requireNonNull(elements, "elements is null"); HashArrayMappedTrie removed = HashArrayMappedTrie.empty(); for (T element : elements) { removed = removed.put(element, element); } HashArrayMappedTrie result = HashArrayMappedTrie.empty(); boolean found = false; for (int i = 0; i < length(); i++) { T element = get(i); if (removed.get(element).isDefined()) { found = true; } else { result = result.put(result.size(), element); } } return found ? wrap(result) : this; } @Override public Vector replace(T currentElement, T newElement) { HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); boolean found = false; for (int i = 0; i < length(); i++) { final T value = get(i); if (found) { trie = trie.put(trie.size(), value); } else { if (currentElement.equals(value)) { trie = trie.put(trie.size(), newElement); found = true; } else { trie = trie.put(trie.size(), value); } } } return found ? new Vector<>(trie) : this; } @Override public Vector replaceAll(T currentElement, T newElement) { HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); boolean changed = false; for (int i = 0; i < length(); i++) { final T value = get(i); if (currentElement.equals(value)) { trie = trie.put(trie.size(), newElement); changed = true; } else { trie = trie.put(trie.size(), value); } } return changed ? wrap(trie) : this; } @SuppressWarnings("unchecked") @Override public Vector retainAll(Iterable elements) { Objects.requireNonNull(elements, "elements is null"); // TODO(Eclipse bug): remove cast + SuppressWarnings final Vector kept = (Vector) (Object) Vector.ofAll(elements).distinct(); HashArrayMappedTrie result = HashArrayMappedTrie.empty(); for (T element : this) { if (kept.contains(element)) { result = result.put(result.size(), element); } } return result.size() == trie.size() ? this : wrap(result); } @Override public Vector reverse() { HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i < length(); i++) { trie = trie.put(i, get(length() - 1 - i)); } return trie.isEmpty() ? empty() : new Vector<>(trie); } @Override public Vector scan(T zero, BiFunction operation) { return scanLeft(zero, operation); } @Override public Vector scanLeft(U zero, BiFunction operation) { Objects.requireNonNull(operation, "operation is null"); return Collections.scanLeft(this, zero, operation, Vector.empty(), Vector::append, Function.identity()); } @Override public Vector scanRight(U zero, BiFunction operation) { Objects.requireNonNull(operation, "operation is null"); return Collections.scanRight(this, zero, operation, Vector.empty(), Vector::prepend, Function.identity()); } @Override public Vector slice(long beginIndex, long endIndex) { if (beginIndex >= endIndex || beginIndex >= length() || isEmpty()) { return Vector.empty(); } if (beginIndex <= 0 && endIndex >= length()) { return this; } final long index = Math.max(beginIndex, 0); final long length = Math.min(endIndex, length()); HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = (int) index; i < length; i++) { trie = trie.put(trie.size(), get(i)); } return wrap(trie); } @Override public Iterator> sliding(long size) { return sliding(size, 1); } @Override public Iterator> sliding(long size, long step) { return iterator().sliding(size, step).map(Vector::ofAll); } @Override public Vector sorted() { return isEmpty() ? this : toJavaStream().sorted().collect(Vector.collector()); } @Override public Vector sorted(Comparator comparator) { Objects.requireNonNull(comparator, "comparator is null"); return isEmpty() ? this : toJavaStream().sorted(comparator).collect(Vector.collector()); } @Override public > Vector sortBy(Function mapper) { return sortBy(U::compareTo, mapper); } @Override public Vector sortBy(Comparator comparator, Function mapper) { final Function domain = Function1.of(mapper::apply).memoized(); return toJavaStream() .sorted((e1, e2) -> comparator.compare(domain.apply(e1), domain.apply(e2))) .collect(collector()); } @Override public Tuple2, Vector> span(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); return Tuple.of(takeWhile(predicate), dropWhile(predicate)); } @Override public Tuple2, Vector> splitAt(long n) { return Tuple.of(take(n), drop(n)); } @Override public Tuple2, Vector> splitAt(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); final Vector init = takeWhile(predicate.negate()); return Tuple.of(init, drop(init.length())); } @Override public Tuple2, Vector> splitAtInclusive(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); HashArrayMappedTrie init = HashArrayMappedTrie.empty(); for (T t : this) { init = init.put(init.size(), t); if (predicate.test(t)) { if (init.size() == length()) { Tuple.of(this, empty()); } else { return Tuple.of(new Vector<>(init), drop(init.size())); } } } return Tuple.of(this, empty()); } @Override public Spliterator spliterator() { return Spliterators.spliterator(iterator(), length(), Spliterator.ORDERED | Spliterator.IMMUTABLE); } @Override public Vector subSequence(int beginIndex) { if (beginIndex < 0) { throw new IndexOutOfBoundsException("slice(" + beginIndex + ")"); } if (beginIndex > length()) { throw new IndexOutOfBoundsException("slice(" + beginIndex + ")"); } return drop(beginIndex); } @Override public Vector subSequence(int beginIndex, int endIndex) { if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) { throw new IndexOutOfBoundsException( String.format("slice(%s, %s) on List of length %s", beginIndex, endIndex, length())); } if (beginIndex == endIndex) { return Vector.empty(); } HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = beginIndex; i < endIndex; i++) { trie = trie.put(trie.size(), get(i)); } return wrap(trie); } @Override public Vector tail() { if (isEmpty()) { throw new UnsupportedOperationException("tail of empty vector"); } if (length() == 1) { return empty(); } else { final int newIndexShift = indexShift + 1; return new Vector<>(newIndexShift, trie.remove(indexShift)); } } @Override public Option> tailOption() { return isEmpty() ? Option.none() : Option.some(tail()); } @Override public Vector take(long n) { if (n >= length()) { return this; } if (n <= 0) { return empty(); } HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i < n; i++) { trie = trie.put(i, get(i)); } return new Vector<>(trie); } @Override public Vector takeRight(long n) { if (n >= length()) { return this; } if (n <= 0) { return empty(); } HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i < n; i++) { trie = trie.put(i, get(length() - (int) n + i)); } return new Vector<>(trie); } @Override public Vector takeUntil(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); return takeWhile(predicate.negate()); } @Override public Vector takeWhile(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); HashArrayMappedTrie trie = HashArrayMappedTrie.empty(); for (int i = 0; i < length(); i++) { T value = get(i); if (!predicate.test(value)) { break; } trie = trie.put(i, get(i)); } return trie.size() == length() ? this : wrap(trie); } /** * Transforms this {@code Vector}. * * @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, ? extends U> f) { Objects.requireNonNull(f, "f is null"); return f.apply(this); } @Override public Vector unit(Iterable iterable) { return Vector.ofAll(iterable); } @Override public Tuple2, Vector> unzip( Function> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); HashArrayMappedTrie xs = HashArrayMappedTrie.empty(); HashArrayMappedTrie ys = HashArrayMappedTrie.empty(); for (T element : this) { final Tuple2 t = unzipper.apply(element); xs = xs.put(xs.size(), t._1); ys = ys.put(ys.size(), t._2); } return Tuple.of(new Vector<>(xs), new Vector<>(ys)); } @Override public Tuple3, Vector, Vector> unzip3(Function> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); HashArrayMappedTrie xs = HashArrayMappedTrie.empty(); HashArrayMappedTrie ys = HashArrayMappedTrie.empty(); HashArrayMappedTrie zs = HashArrayMappedTrie.empty(); for (T element : this) { final Tuple3 t = unzipper.apply(element); xs = xs.put(xs.size(), t._1); ys = ys.put(ys.size(), t._2); zs = zs.put(zs.size(), t._3); } return Tuple.of(new Vector<>(xs), new Vector<>(ys), new Vector<>(zs)); } @Override public Vector update(int index, T element) { if (index < 0) { throw new IndexOutOfBoundsException("update(" + index + ")"); } if (index >= length()) { throw new IndexOutOfBoundsException("update(" + index + ")"); } return new Vector<>(indexShift, trie.put(index + indexShift, element)); } @Override public Vector> zip(Iterable that) { Objects.requireNonNull(that, "that is null"); return Vector.ofAll(iterator().zip(that)); } @Override public Vector> zipAll(Iterable that, T thisElem, U thatElem) { Objects.requireNonNull(that, "that is null"); return Vector.ofAll(iterator().zipAll(that, thisElem, thatElem)); } @Override public Vector> zipWithIndex() { return Vector.ofAll(iterator().zipWithIndex()); } private Object readResolve() { return isEmpty() ? EMPTY : this; } @Override public boolean equals(Object o) { if (o == this) { return true; } else if (o instanceof Vector) { final Vector that = (Vector) o; return (this.size() == that.size()) && Collections.equals(this, that); } else { return false; } } @Override public int hashCode() { return Collections.hash(this); } @Override public String stringPrefix() { return "Vector"; } @Override public String toString() { return mkString(stringPrefix() + "(", ", ", ")"); } private static Vector wrap(HashArrayMappedTrie trie) { return trie.isEmpty() ? empty() : new Vector<>(trie); } } interface VectorModule { final class Combinations { static Vector> apply(Vector elements, int k) { if (k == 0) { return Vector.of(Vector.empty()); } else { return elements.zipWithIndex().flatMap(t -> apply(elements.drop(t._2 + 1), (k - 1)) .map((Vector c) -> c.prepend(t._1)) ); } } } }