/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.collect.array;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.RandomAccess;
import java.util.Set;
import java.util.function.DoubleBinaryOperator;
import java.util.function.DoubleUnaryOperator;
import java.util.function.IntToDoubleFunction;
import java.util.stream.DoubleStream;
import org.joda.beans.Bean;
import org.joda.beans.BeanBuilder;
import org.joda.beans.ImmutableBean;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaBean;
import org.joda.beans.MetaProperty;
import org.joda.beans.Property;
import org.joda.beans.PropertyStyle;
import org.joda.beans.impl.BasicImmutableBeanBuilder;
import org.joda.beans.impl.BasicMetaBean;
import org.joda.beans.impl.BasicMetaProperty;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.primitives.Doubles;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.DoubleArrayMath;
import com.opengamma.strata.collect.function.DoubleTernaryOperator;
import com.opengamma.strata.collect.function.IntDoubleConsumer;
import com.opengamma.strata.collect.function.IntDoubleToDoubleFunction;
/**
* An immutable array of {@code double} values.
* <p>
* This provides functionality similar to {@link List} but for {@code double[]}.
* <p>
* In mathematical terms, this is a vector, or one-dimensional matrix.
*/
public final class DoubleArray
implements Matrix, ImmutableBean, Serializable {
/**
* An empty array.
*/
public static final DoubleArray EMPTY = new DoubleArray(new double[0]);
/**
* Serialization version.
*/
private static final long serialVersionUID = 1L;
static {
JodaBeanUtils.registerMetaBean(Meta.META);
}
/**
* The underlying array of doubles.
*/
private final double[] array;
//-------------------------------------------------------------------------
/**
* Obtains an empty immutable array.
*
* @return the empty immutable array
*/
public static DoubleArray of() {
return EMPTY;
}
/**
* Obtains an immutable array with a single value.
*
* @param value the single value
* @return an array containing the specified value
*/
public static DoubleArray of(double value) {
return new DoubleArray(new double[] {value});
}
/**
* Obtains an immutable array with two values.
*
* @param value1 the first value
* @param value2 the second value
* @return an array containing the specified values
*/
public static DoubleArray of(double value1, double value2) {
return new DoubleArray(new double[] {value1, value2});
}
/**
* Obtains an immutable array with three values.
*
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value
* @return an array containing the specified values
*/
public static DoubleArray of(double value1, double value2, double value3) {
return new DoubleArray(new double[] {value1, value2, value3});
}
/**
* Obtains an immutable array with four values.
*
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value
* @param value4 the fourth value
* @return an array containing the specified values
*/
public static DoubleArray of(double value1, double value2, double value3, double value4) {
return new DoubleArray(new double[] {value1, value2, value3, value4});
}
/**
* Obtains an immutable array with five values.
*
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value
* @param value4 the fourth value
* @param value5 the fifth value
* @return an array containing the specified values
*/
public static DoubleArray of(
double value1, double value2, double value3, double value4, double value5) {
return new DoubleArray(new double[] {value1, value2, value3, value4, value5});
}
/**
* Obtains an immutable array with six values.
*
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value
* @param value4 the fourth value
* @param value5 the fifth value
* @param value6 the sixth value
* @return an array containing the specified values
*/
public static DoubleArray of(
double value1, double value2, double value3, double value4,
double value5, double value6) {
return new DoubleArray(new double[] {value1, value2, value3, value4, value5, value6});
}
/**
* Obtains an immutable array with seven values.
*
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value
* @param value4 the fourth value
* @param value5 the fifth value
* @param value6 the sixth value
* @param value7 the seventh value
* @return an array containing the specified values
*/
public static DoubleArray of(
double value1, double value2, double value3, double value4,
double value5, double value6, double value7) {
return new DoubleArray(new double[] {value1, value2, value3, value4, value5, value6, value7});
}
/**
* Obtains an immutable array with eight values.
*
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value
* @param value4 the fourth value
* @param value5 the fifth value
* @param value6 the sixth value
* @param value7 the seventh value
* @param value8 the eighth value
* @return an array containing the specified values
*/
public static DoubleArray of(
double value1, double value2, double value3, double value4,
double value5, double value6, double value7, double value8) {
return new DoubleArray(new double[] {value1, value2, value3, value4, value5, value6, value7, value8});
}
/**
* Obtains an immutable array with more than eight values.
*
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value
* @param value4 the fourth value
* @param value5 the fifth value
* @param value6 the sixth value
* @param value7 the seventh value
* @param value8 the eighth value
* @param otherValues the other values
* @return an array containing the specified values
*/
public static DoubleArray of(
double value1, double value2, double value3, double value4,
double value5, double value6, double value7, double value8, double... otherValues) {
double[] base = new double[otherValues.length + 8];
base[0] = value1;
base[1] = value2;
base[2] = value3;
base[3] = value4;
base[4] = value5;
base[5] = value6;
base[6] = value7;
base[7] = value8;
System.arraycopy(otherValues, 0, base, 8, otherValues.length);
return new DoubleArray(base);
}
//-------------------------------------------------------------------------
/**
* Obtains an instance with entries filled using a function.
* <p>
* The function is passed the array index and returns the value for that index.
*
* @param size the number of elements
* @param valueFunction the function used to populate the value
* @return an array initialized using the function
*/
public static DoubleArray of(int size, IntToDoubleFunction valueFunction) {
if (size == 0) {
return EMPTY;
}
double[] array = new double[size];
Arrays.setAll(array, valueFunction);
return new DoubleArray(array);
}
/**
* Obtains an instance by wrapping an array.
* <p>
* This method is inherently unsafe as it relies on good behavior by callers.
* Callers must never make any changes to the passed in array after calling this method.
* Doing so would violate the immutability of this class.
*
* @param array the array to assign
* @return an array instance wrapping the specified array
*/
public static DoubleArray ofUnsafe(double[] array) {
if (array.length == 0) {
return EMPTY;
}
return new DoubleArray(array);
}
//-----------------------------------------------------------------------
/**
* Obtains an instance from a collection of {@code Double}.
* <p>
* The order of the values in the returned array is the order in which elements are returned
* from the iterator of the collection.
*
* @param collection the collection to initialize from
* @return an array containing the values from the collection in iteration order
*/
public static DoubleArray copyOf(Collection<Double> collection) {
if (collection.size() == 0) {
return EMPTY;
}
if (collection instanceof ImmList) {
return ((ImmList) collection).underlying;
}
return new DoubleArray(Doubles.toArray(collection));
}
/**
* Obtains an instance from an array of {@code double}.
* <p>
* The input array is copied and not mutated.
*
* @param array the array to copy, cloned
* @return an array containing the specified values
*/
public static DoubleArray copyOf(double[] array) {
if (array.length == 0) {
return EMPTY;
}
return new DoubleArray(array.clone());
}
/**
* Obtains an instance by copying part of an array.
* <p>
* The input array is copied and not mutated.
*
* @param array the array to copy
* @param fromIndex the offset from the start of the array
* @return an array containing the specified values
* @throws IndexOutOfBoundsException if the index is invalid
*/
public static DoubleArray copyOf(double[] array, int fromIndex) {
return copyOf(array, fromIndex, array.length);
}
/**
* Obtains an instance by copying part of an array.
* <p>
* The input array is copied and not mutated.
*
* @param array the array to copy
* @param fromIndexInclusive the start index of the input array to copy from
* @param toIndexExclusive the end index of the input array to copy to
* @return an array containing the specified values
* @throws IndexOutOfBoundsException if the index is invalid
*/
public static DoubleArray copyOf(double[] array, int fromIndexInclusive, int toIndexExclusive) {
if (fromIndexInclusive > array.length) {
throw new IndexOutOfBoundsException("Array index out of bounds: " + fromIndexInclusive + " > " + array.length);
}
if (toIndexExclusive > array.length) {
throw new IndexOutOfBoundsException("Array index out of bounds: " + toIndexExclusive + " > " + array.length);
}
if ((toIndexExclusive - fromIndexInclusive) == 0) {
return EMPTY;
}
return new DoubleArray(Arrays.copyOfRange(array, fromIndexInclusive, toIndexExclusive));
}
//-------------------------------------------------------------------------
/**
* Obtains an instance with all entries equal to the zero.
*
* @param size the number of elements
* @return an array filled with zeroes
*/
public static DoubleArray filled(int size) {
if (size == 0) {
return EMPTY;
}
return new DoubleArray(new double[size]);
}
/**
* Obtains an instance with all entries equal to the same value.
*
* @param size the number of elements
* @param value the value of all the elements
* @return an array filled with the specified value
*/
public static DoubleArray filled(int size, double value) {
if (size == 0) {
return EMPTY;
}
double[] array = new double[size];
Arrays.fill(array, value);
return new DoubleArray(array);
}
//-------------------------------------------------------------------------
/**
* Creates an instance from a {@code double[}.
*
* @param array the array, assigned not cloned
*/
private DoubleArray(double[] array) {
this.array = array;
}
//-------------------------------------------------------------------------
/**
* Gets the number of dimensions of this array.
*
* @return one
*/
@Override
public int dimensions() {
return 1;
}
/**
* Gets the size of this array.
*
* @return the array size, zero or greater
*/
@Override
public int size() {
return array.length;
}
/**
* Checks if this array is empty.
*
* @return true if empty
*/
public boolean isEmpty() {
return array.length == 0;
}
//-------------------------------------------------------------------------
/**
* Gets the value at the specified index in this array.
*
* @param index the zero-based index to retrieve
* @return the value at the index
* @throws IndexOutOfBoundsException if the index is invalid
*/
public double get(int index) {
return array[index];
}
/**
* Checks if this array contains the specified value.
* <p>
* The value is checked using {@code Double.doubleToLongBits} in order to match {@code equals}.
* This also allow this method to be used to find any occurrences of NaN.
*
* @param value the value to find
* @return true if the value is contained in this array
*/
public boolean contains(double value) {
if (array.length > 0) {
long bits = Double.doubleToLongBits(value);
for (int i = 0; i < array.length; i++) {
if (Double.doubleToLongBits(array[i]) == bits) {
return true;
}
}
}
return false;
}
/**
* Find the index of the first occurrence of the specified value.
* <p>
* The value is checked using {@code Double.doubleToLongBits} in order to match {@code equals}.
* This also allow this method to be used to find any occurrences of NaN.
*
* @param value the value to find
* @return the index of the value, -1 if not found
*/
public int indexOf(double value) {
if (array.length > 0) {
long bits = Double.doubleToLongBits(value);
for (int i = 0; i < array.length; i++) {
if (Double.doubleToLongBits(array[i]) == bits) {
return i;
}
}
}
return -1;
}
/**
* Find the index of the first occurrence of the specified value.
* <p>
* The value is checked using {@code Double.doubleToLongBits} in order to match {@code equals}.
* This also allow this method to be used to find any occurrences of NaN.
*
* @param value the value to find
* @return the index of the value, -1 if not found
*/
public int lastIndexOf(double value) {
if (array.length > 0) {
long bits = Double.doubleToLongBits(value);
for (int i = array.length - 1; i >= 0; i--) {
if (Double.doubleToLongBits(array[i]) == bits) {
return i;
}
}
}
return -1;
}
//-------------------------------------------------------------------------
/**
* Copies this array into the specified array.
* <p>
* The specified array must be at least as large as this array.
* If it is larger, then the remainder of the array will be untouched.
*
* @param destination the array to copy into
* @param offset the offset in the destination array to start from
* @throws IndexOutOfBoundsException if the destination array is not large enough
* or the offset is negative
*/
public void copyInto(double[] destination, int offset) {
if (destination.length < array.length + offset) {
throw new IndexOutOfBoundsException("Destination array is not large enough");
}
System.arraycopy(array, 0, destination, offset, array.length);
}
/**
* Returns an array holding the values from the specified index onwards.
*
* @param fromIndexInclusive the start index of the array to copy from
* @return an array instance with the specified bounds
* @throws IndexOutOfBoundsException if the index is invalid
*/
public DoubleArray subArray(int fromIndexInclusive) {
return subArray(fromIndexInclusive, array.length);
}
/**
* Returns an array holding the values between the specified from and to indices.
*
* @param fromIndexInclusive the start index of the array to copy from
* @param toIndexExclusive the end index of the array to copy to
* @return an array instance with the specified bounds
* @throws IndexOutOfBoundsException if the index is invalid
*/
public DoubleArray subArray(int fromIndexInclusive, int toIndexExclusive) {
return copyOf(array, fromIndexInclusive, toIndexExclusive);
}
//-------------------------------------------------------------------------
/**
* Converts this instance to an independent {@code double[]}.
*
* @return a copy of the underlying array
*/
public double[] toArray() {
return array.clone();
}
/**
* Returns the underlying array.
* <p>
* This method is inherently unsafe as it relies on good behavior by callers.
* Callers must never make any changes to the array returned by this method.
* Doing so would violate the immutability of this class.
*
* @return the raw array
*/
public double[] toArrayUnsafe() {
return array;
}
//-------------------------------------------------------------------------
/**
* Returns a list equivalent to this array.
*
* @return a list wrapping this array
*/
public List<Double> toList() {
return new ImmList(this);
}
/**
* Returns a stream over the array values.
*
* @return a stream over the values in the array
*/
public DoubleStream stream() {
return DoubleStream.of(array);
}
//-------------------------------------------------------------------------
/**
* Applies an action to each value in the array.
* <p>
* This is used to perform an action on the contents of this array.
* The action receives both the index and the value.
* For example, the action could print out the array.
* <pre>
* base.forEach((index, value) -> System.out.println(index + ": " + value));
* </pre>
* <p>
* This instance is immutable and unaffected by this method.
*
* @param action the action to be applied
*/
public void forEach(IntDoubleConsumer action) {
for (int i = 0; i < array.length; i++) {
action.accept(i, array[i]);
}
}
//-----------------------------------------------------------------------
/**
* Returns an instance with the value at the specified index changed.
* <p>
* This instance is immutable and unaffected by this method.
*
* @param index the zero-based index to set
* @param newValue the new value to store
* @return a copy of this array with the value at the index changed
* @throws IndexOutOfBoundsException if the index is invalid
*/
public DoubleArray with(int index, double newValue) {
if (Double.doubleToLongBits(array[index]) == Double.doubleToLongBits(newValue)) {
return this;
}
double[] result = array.clone();
result[index] = newValue;
return new DoubleArray(result);
}
//-------------------------------------------------------------------------
/**
* Returns an instance with the specified amount added to each value.
* <p>
* This is used to add to the contents of this array, returning a new array.
* <p>
* This is a special case of {@link #map(DoubleUnaryOperator)}.
* This instance is immutable and unaffected by this method.
*
* @param amount the amount to add, may be negative
* @return a copy of this array with the amount added to each value
*/
public DoubleArray plus(double amount) {
if (amount == 0d) {
return this;
}
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i] + amount;
}
return new DoubleArray(result);
}
/**
* Returns an instance with the specified amount subtracted from each value.
* <p>
* This is used to subtract from the contents of this array, returning a new array.
* <p>
* This is a special case of {@link #map(DoubleUnaryOperator)}.
* This instance is immutable and unaffected by this method.
*
* @param amount the amount to subtract, may be negative
* @return a copy of this array with the amount subtracted from each value
*/
public DoubleArray minus(double amount) {
if (amount == 0d) {
return this;
}
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i] - amount;
}
return new DoubleArray(result);
}
/**
* Returns an instance with each value multiplied by the specified factor.
* <p>
* This is used to multiply the contents of this array, returning a new array.
* <p>
* This is a special case of {@link #map(DoubleUnaryOperator)}.
* This instance is immutable and unaffected by this method.
*
* @param factor the multiplicative factor
* @return a copy of this array with the each value multiplied by the factor
*/
public DoubleArray multipliedBy(double factor) {
if (factor == 1d) {
return this;
}
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i] * factor;
}
return new DoubleArray(result);
}
/**
* Returns an instance with each value divided by the specified divisor.
* <p>
* This is used to divide the contents of this array, returning a new array.
* <p>
* This is a special case of {@link #map(DoubleUnaryOperator)}.
* This instance is immutable and unaffected by this method.
*
* @param divisor the value by which the array values are divided
* @return a copy of this array with the each value divided by the divisor
*/
public DoubleArray dividedBy(double divisor) {
if (divisor == 1d) {
return this;
}
// multiplication is cheaper than division so it is more efficient to do the division once and multiply each element
double factor = 1 / divisor;
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i] * factor;
}
return new DoubleArray(result);
}
/**
* Returns an instance with an operation applied to each value in the array.
* <p>
* This is used to perform an operation on the contents of this array, returning a new array.
* The operator only receives the value.
* For example, the operator could take the inverse of each element.
* <pre>
* result = base.map(value -> 1 / value);
* </pre>
* <p>
* This instance is immutable and unaffected by this method.
*
* @param operator the operator to be applied
* @return a copy of this array with the operator applied to the original values
*/
public DoubleArray map(DoubleUnaryOperator operator) {
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = operator.applyAsDouble(array[i]);
}
return new DoubleArray(result);
}
/**
* Returns an instance with an operation applied to each indexed value in the array.
* <p>
* This is used to perform an operation on the contents of this array, returning a new array.
* The function receives both the index and the value.
* For example, the operator could multiply the value by the index.
* <pre>
* result = base.mapWithIndex((index, value) -> index * value);
* </pre>
* <p>
* This instance is immutable and unaffected by this method.
*
* @param function the function to be applied
* @return a copy of this array with the operator applied to the original values
*/
public DoubleArray mapWithIndex(IntDoubleToDoubleFunction function) {
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = function.applyAsDouble(i, array[i]);
}
return new DoubleArray(result);
}
//-------------------------------------------------------------------------
/**
* Returns an instance where each element is the sum of the matching values
* in this array and the other array.
* <p>
* This is used to add two arrays, returning a new array.
* Element {@code n} in the resulting array is equal to element {@code n} in this array
* plus element {@code n} in the other array.
* The arrays must be of the same size.
* <p>
* This is a special case of {@link #combine(DoubleArray, DoubleBinaryOperator)}.
* This instance is immutable and unaffected by this method.
*
* @param other the other array
* @return a copy of this array with matching elements added
* @throws IllegalArgumentException if the arrays have different sizes
*/
public DoubleArray plus(DoubleArray other) {
if (array.length != other.array.length) {
throw new IllegalArgumentException("Arrays have different sizes");
}
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i] + other.array[i];
}
return new DoubleArray(result);
}
/**
* Returns an instance where each element is equal to the difference between the
* matching values in this array and the other array.
* <p>
* This is used to subtract the second array from the first, returning a new array.
* Element {@code n} in the resulting array is equal to element {@code n} in this array
* minus element {@code n} in the other array.
* The arrays must be of the same size.
* <p>
* This is a special case of {@link #combine(DoubleArray, DoubleBinaryOperator)}.
* This instance is immutable and unaffected by this method.
*
* @param other the other array
* @return a copy of this array with matching elements subtracted
* @throws IllegalArgumentException if the arrays have different sizes
*/
public DoubleArray minus(DoubleArray other) {
if (array.length != other.array.length) {
throw new IllegalArgumentException("Arrays have different sizes");
}
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i] - other.array[i];
}
return new DoubleArray(result);
}
/**
* Returns an instance where each element is equal to the product of the
* matching values in this array and the other array.
* <p>
* This is used to multiply each value in this array by the corresponding value in the other array,
* returning a new array.
* <p>
* Element {@code n} in the resulting array is equal to element {@code n} in this array
* multiplied by element {@code n} in the other array.
* The arrays must be of the same size.
* <p>
* This is a special case of {@link #combine(DoubleArray, DoubleBinaryOperator)}.
* This instance is immutable and unaffected by this method.
*
* @param other the other array
* @return a copy of this array with matching elements multiplied
* @throws IllegalArgumentException if the arrays have different sizes
*/
public DoubleArray multipliedBy(DoubleArray other) {
if (array.length != other.array.length) {
throw new IllegalArgumentException("Arrays have different sizes");
}
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i] * other.array[i];
}
return new DoubleArray(result);
}
/**
* Returns an instance where each element is calculated by dividing values in this array by values in the other array.
* <p>
* This is used to divide each value in this array by the corresponding value in the other array,
* returning a new array.
* <p>
* Element {@code n} in the resulting array is equal to element {@code n} in this array
* divided by element {@code n} in the other array.
* The arrays must be of the same size.
* <p>
* This is a special case of {@link #combine(DoubleArray, DoubleBinaryOperator)}.
* This instance is immutable and unaffected by this method.
*
* @param other the other array
* @return a copy of this array with matching elements divided
* @throws IllegalArgumentException if the arrays have different sizes
*/
public DoubleArray dividedBy(DoubleArray other) {
if (array.length != other.array.length) {
throw new IllegalArgumentException("Arrays have different sizes");
}
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i] / other.array[i];
}
return new DoubleArray(result);
}
/**
* Returns an instance where each element is formed by some combination of the matching
* values in this array and the other array.
* <p>
* This is used to combine two arrays, returning a new array.
* Element {@code n} in the resulting array is equal to the result of the operator
* when applied to element {@code n} in this array and element {@code n} in the other array.
* The arrays must be of the same size.
* <p>
* This instance is immutable and unaffected by this method.
*
* @param other the other array
* @param operator the operator used to combine each pair of values
* @return a copy of this array combined with the specified array
* @throws IllegalArgumentException if the arrays have different sizes
*/
public DoubleArray combine(DoubleArray other, DoubleBinaryOperator operator) {
if (array.length != other.array.length) {
throw new IllegalArgumentException("Arrays have different sizes");
}
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = operator.applyAsDouble(array[i], other.array[i]);
}
return new DoubleArray(result);
}
/**
* Combines this array and the other array returning a reduced value.
* <p>
* This is used to combine two arrays, returning a single reduced value.
* The operator is called once for each element in the arrays.
* The arrays must be of the same size.
* <p>
* The first argument to the operator is the running total of the reduction, starting from zero.
* The second argument to the operator is the element from this array.
* The third argument to the operator is the element from the other array.
* <p>
* This instance is immutable and unaffected by this method.
*
* @param other the other array
* @param operator the operator used to combine each pair of values with the current total
* @return the result of the reduction
* @throws IllegalArgumentException if the arrays have different sizes
*/
public double combineReduce(DoubleArray other, DoubleTernaryOperator operator) {
if (array.length != other.array.length) {
throw new IllegalArgumentException("Arrays have different sizes");
}
double result = 0;
for (int i = 0; i < array.length; i++) {
result = operator.applyAsDouble(result, array[i], other.array[i]);
}
return result;
}
//-------------------------------------------------------------------------
/**
* Returns an array that combines this array and the specified array.
* <p>
* The result will have a length equal to {@code this.size() + arrayToConcat.length}.
* <p>
* This instance is immutable and unaffected by this method.
*
* @param arrayToConcat the array to add to the end of this array
* @return a copy of this array with the specified array added at the end
* @throws IndexOutOfBoundsException if the index is invalid
*/
public DoubleArray concat(double... arrayToConcat) {
if (array.length == 0) {
return copyOf(arrayToConcat);
}
if (arrayToConcat.length == 0) {
return this;
}
double[] result = new double[array.length + arrayToConcat.length];
System.arraycopy(array, 0, result, 0, array.length);
System.arraycopy(arrayToConcat, 0, result, array.length, arrayToConcat.length);
return new DoubleArray(result);
}
/**
* Returns an array that combines this array and the specified array.
* <p>
* The result will have a length equal to {@code this.size() + newArray.length}.
* <p>
* This instance is immutable and unaffected by this method.
*
* @param arrayToConcat the new array to add to the end of this array
* @return a copy of this array with the specified array added at the end
* @throws IndexOutOfBoundsException if the index is invalid
*/
public DoubleArray concat(DoubleArray arrayToConcat) {
if (array.length == 0) {
return arrayToConcat;
}
if (arrayToConcat.array.length == 0) {
return this;
}
return concat(arrayToConcat.array);
}
//-----------------------------------------------------------------------
/**
* Returns a sorted copy of this array.
* <p>
* This uses {@link Arrays#sort(double[])}.
* <p>
* This instance is immutable and unaffected by this method.
*
* @return a sorted copy of this array
*/
public DoubleArray sorted() {
if (array.length < 2) {
return this;
}
double[] result = array.clone();
Arrays.sort(result);
return new DoubleArray(result);
}
/**
* Returns the minimum value held in the array.
* <p>
* If the array is empty, then an exception is thrown.
* If the array contains NaN, then the result is NaN.
*
* @return the minimum value
* @throws IllegalStateException if the array is empty
*/
public double min() {
if (array.length == 0) {
throw new IllegalStateException("Unable to find minimum of an empty array");
}
if (array.length == 1) {
return array[0];
}
double min = Double.POSITIVE_INFINITY;
for (int i = 0; i < array.length; i++) {
min = Math.min(min, array[i]);
}
return min;
}
/**
* Returns the minimum value held in the array.
* <p>
* If the array is empty, then an exception is thrown.
* If the array contains NaN, then the result is NaN.
*
* @return the maximum value
* @throws IllegalStateException if the array is empty
*/
public double max() {
if (array.length == 0) {
throw new IllegalStateException("Unable to find maximum of an empty array");
}
if (array.length == 1) {
return array[0];
}
double max = Double.NEGATIVE_INFINITY;
for (int i = 0; i < array.length; i++) {
max = Math.max(max, array[i]);
}
return max;
}
/**
* Returns the sum of all the values in the array.
* <p>
* This is a special case of {@link #reduce(double, DoubleBinaryOperator)}.
*
* @return the total of all the values
*/
public double sum() {
double total = 0;
for (int i = 0; i < array.length; i++) {
total += array[i];
}
return total;
}
/**
* Reduces this array returning a single value.
* <p>
* This is used to reduce the values in this array to a single value.
* The operator is called once for each element in the arrays.
* The first argument to the operator is the running total of the reduction, starting from zero.
* The second argument to the operator is the element.
* <p>
* This instance is immutable and unaffected by this method.
*
* @param identity the identity value to start from
* @param operator the operator used to combine the value with the current total
* @return the result of the reduction
*/
public double reduce(double identity, DoubleBinaryOperator operator) {
double result = identity;
for (int i = 0; i < array.length; i++) {
result = operator.applyAsDouble(result, array[i]);
}
return result;
}
//-------------------------------------------------------------------------
@Override
public MetaBean metaBean() {
return Meta.META;
}
@Override
public <R> Property<R> property(String propertyName) {
return metaBean().<R>metaProperty(propertyName).createProperty(this);
}
@Override
public Set<String> propertyNames() {
return metaBean().metaPropertyMap().keySet();
}
//-------------------------------------------------------------------------
/**
* Checks if this array equals another within the specified tolerance.
* <p>
* This returns true if the two instances have {@code double} values that are
* equal within the specified tolerance.
*
* @param other the other array
* @param tolerance the tolerance
* @return true if equal up to the tolerance
*/
public boolean equalWithTolerance(DoubleArray other, double tolerance) {
return DoubleArrayMath.fuzzyEquals(array, other.array, tolerance);
}
/**
* Checks if this array equals zero within the specified tolerance.
* <p>
* This returns true if all the {@code double} values equal zero within the specified tolerance.
*
* @param tolerance the tolerance
* @return true if equal up to the tolerance
*/
public boolean equalZeroWithTolerance(double tolerance) {
return DoubleArrayMath.fuzzyEqualsZero(array, tolerance);
}
//-------------------------------------------------------------------------
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DoubleArray) {
DoubleArray other = (DoubleArray) obj;
return Arrays.equals(array, other.array);
}
return false;
}
@Override
public int hashCode() {
return Arrays.hashCode(array);
}
@Override
public String toString() {
return Arrays.toString(array);
}
//-----------------------------------------------------------------------
/**
* Immutable {@code Iterator} representation of the array.
*/
static class ImmIterator implements ListIterator<Double> {
private final double[] array;
private int index;
public ImmIterator(double[] array) {
this.array = array;
}
@Override
public boolean hasNext() {
return index < array.length;
}
@Override
public boolean hasPrevious() {
return index > 0;
}
@Override
public Double next() {
if (hasNext()) {
return array[index++];
}
throw new NoSuchElementException("Iteration has reached the last element");
}
@Override
public Double previous() {
if (hasPrevious()) {
return array[--index];
}
throw new NoSuchElementException("Iteration has reached the first element");
}
@Override
public int nextIndex() {
return index;
}
@Override
public int previousIndex() {
return index - 1;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Unable to remove from DoubleArray");
}
@Override
public void set(Double value) {
throw new UnsupportedOperationException("Unable to set value in DoubleArray");
}
@Override
public void add(Double value) {
throw new UnsupportedOperationException("Unable to add value to DoubleArray");
}
}
//-----------------------------------------------------------------------
/**
* Immutable {@code List} representation of the array.
*/
static class ImmList extends AbstractList<Double> implements RandomAccess, Serializable {
private static final long serialVersionUID = 1L;
private final DoubleArray underlying;
ImmList(DoubleArray underlying) {
this.underlying = underlying;
}
@Override
public int size() {
return underlying.size();
}
@Override
public Double get(int index) {
return underlying.get(index);
}
@Override
public boolean contains(Object obj) {
return (obj instanceof Double ? underlying.contains((Double) obj) : false);
}
@Override
public int indexOf(Object obj) {
return (obj instanceof Double ? underlying.indexOf((Double) obj) : -1);
}
@Override
public int lastIndexOf(Object obj) {
return (obj instanceof Double ? underlying.lastIndexOf((Double) obj) : -1);
}
@Override
public ListIterator<Double> iterator() {
return listIterator();
}
@Override
public ListIterator<Double> listIterator() {
return new ImmIterator(underlying.array);
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
throw new UnsupportedOperationException("Unable to remove range from DoubleArray");
}
}
//-------------------------------------------------------------------------
/**
* Meta bean.
*/
static final class Meta extends BasicMetaBean {
private static final MetaBean META = new Meta();
private static final MetaProperty<double[]> ARRAY = new BasicMetaProperty<double[]>("array") {
@Override
public MetaBean metaBean() {
return META;
}
@Override
public Class<?> declaringType() {
return DoubleArray.class;
}
@Override
public Class<double[]> propertyType() {
return double[].class;
}
@Override
public Type propertyGenericType() {
return double[].class;
}
@Override
public PropertyStyle style() {
return PropertyStyle.IMMUTABLE;
}
@Override
public List<Annotation> annotations() {
return ImmutableList.of();
}
@Override
public double[] get(Bean bean) {
return ((DoubleArray) bean).toArray();
}
@Override
public void set(Bean bean, Object value) {
throw new UnsupportedOperationException("Property cannot be written: " + name());
}
};
private static final ImmutableMap<String, MetaProperty<?>> MAP = ImmutableMap.of("array", ARRAY);
private Meta() {
}
@Override
public BeanBuilder<DoubleArray> builder() {
return new BasicImmutableBeanBuilder<DoubleArray>(this) {
private double[] array = DoubleArrayMath.EMPTY_DOUBLE_ARRAY;
@Override
public Object get(String propertyName) {
if (propertyName.equals(ARRAY.name())) {
return array.clone();
} else {
throw new NoSuchElementException("Unknown property: " + propertyName);
}
}
@Override
public BeanBuilder<DoubleArray> set(String propertyName, Object value) {
if (propertyName.equals(ARRAY.name())) {
this.array = ((double[]) ArgChecker.notNull(value, "value")).clone();
} else {
throw new NoSuchElementException("Unknown property: " + propertyName);
}
return this;
}
@Override
public DoubleArray build() {
return new DoubleArray(array);
}
};
}
@Override
public Class<? extends Bean> beanType() {
return DoubleArray.class;
}
@Override
public Map<String, MetaProperty<?>> metaPropertyMap() {
return MAP;
}
}
}