/*******************************************************************************
* Breakout Cave Survey Visualizer
*
* Copyright (C) 2014 James Edwards
*
* jedwards8 at fastmail dot fm
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*******************************************************************************/
package org.andork.util;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.function.Function;
import java.util.function.Predicate;
import org.andork.func.ThrowingDoubleFunction;
import org.andork.func.ThrowingFunction;
import org.andork.func.ThrowingToDoubleFunction;
public class ArrayUtils {
public static String cat(Object[] o, String delimiter) {
StringBuffer sb = new StringBuffer();
if (o.length > 0) {
sb.append(o[0]);
}
for (int i = 1; i < o.length; i++) {
sb.append(delimiter).append(o[i]);
}
return sb.toString();
}
/**
* Changes the block size of an array, i.e. pads or truncates blocks of
* elements.
*/
public static byte[] changeBlockSize(byte[] src, int srcBlockSize, int destBlockSize) {
if (src.length % srcBlockSize != 0) {
throw new IllegalArgumentException("src does not have a block size of " + srcBlockSize);
}
final byte[] dest = new byte[src.length * destBlockSize / srcBlockSize];
final int minBlockSize = Math.min(srcBlockSize, destBlockSize);
final int srcPad = srcBlockSize - destBlockSize;
final int destPad = destBlockSize - srcBlockSize;
int s = 0, d = 0;
if (srcPad > 0) {
while (s < src.length) {
System.arraycopy(src, s, dest, d, minBlockSize);
s += minBlockSize + srcPad;
d += minBlockSize;
}
} else if (destPad > 0) {
while (s < src.length) {
System.arraycopy(src, s, dest, d, minBlockSize);
s += minBlockSize;
d += minBlockSize + destPad;
}
} else {
System.arraycopy(src, 0, dest, 0, src.length);
}
return dest;
}
/**
* Changes the block size of an array, i.e. pads or truncates blocks of
* elements.
*/
public static double[] changeBlockSize(double[] src, int srcBlockSize, int destBlockSize) {
if (src.length % srcBlockSize != 0) {
throw new IllegalArgumentException("src does not have a block size of " + srcBlockSize);
}
final double[] dest = new double[src.length * destBlockSize / srcBlockSize];
final int minBlockSize = Math.min(srcBlockSize, destBlockSize);
final int srcPad = srcBlockSize - destBlockSize;
final int destPad = destBlockSize - srcBlockSize;
int s = 0, d = 0;
if (srcPad > 0) {
while (s < src.length) {
System.arraycopy(src, s, dest, d, minBlockSize);
s += minBlockSize + srcPad;
d += minBlockSize;
}
} else if (destPad > 0) {
while (s < src.length) {
System.arraycopy(src, s, dest, d, minBlockSize);
s += minBlockSize;
d += minBlockSize + destPad;
}
} else {
System.arraycopy(src, 0, dest, 0, src.length);
}
return dest;
}
/**
* Changes the block size of an array, i.e. pads or truncates blocks of
* elements.
*/
public static float[] changeBlockSize(float[] src, int srcBlockSize, int destBlockSize) {
if (src.length % srcBlockSize != 0) {
throw new IllegalArgumentException("src does not have a block size of " + srcBlockSize);
}
final float[] dest = new float[src.length * destBlockSize / srcBlockSize];
final int minBlockSize = Math.min(srcBlockSize, destBlockSize);
final int srcPad = srcBlockSize - destBlockSize;
final int destPad = destBlockSize - srcBlockSize;
int s = 0, d = 0;
if (srcPad > 0) {
while (s < src.length) {
System.arraycopy(src, s, dest, d, minBlockSize);
s += minBlockSize + srcPad;
d += minBlockSize;
}
} else if (destPad > 0) {
while (s < src.length) {
System.arraycopy(src, s, dest, d, minBlockSize);
s += minBlockSize;
d += minBlockSize + destPad;
}
} else {
System.arraycopy(src, 0, dest, 0, src.length);
}
return dest;
}
public static boolean contains(Object[] values, Object target) {
return indexOf(values, target) >= 0;
}
public static <T> T[] copyOf(T[] original) {
return Arrays.copyOf(original, original.length);
}
/**
* Finds the index of a double in an arbitrary-order double array.
*
* @param values
* an array of doubles with arbitrary order.
* @param a
* the value to search for. This method always returns {@code -1}
* if {@code NaN} is given.
* @return the lowest index of any non-{@code NaN} element in {@code values}
* that {@code == a}, or {@code -1} otherwise.
*/
public static int indexOf(double[] values, double a) {
for (int i = 0; i < values.length; i++) {
if (values[i] == a) {
return i;
}
}
return -1;
}
/**
* Finds the index of a int in an arbitrary-order int array.
*
* @param values
* an array of ints with arbitrary order.
* @param a
* the value to search for.
* @return the lowest index of any element in {@code values} that
* {@code == a}, or {@code -1} otherwise.
*/
public static int indexOf(int[] values, int a) {
for (int i = 0; i < values.length; i++) {
if (values[i] == a) {
return i;
}
}
return -1;
}
/**
* Finds the index of an equivalent {@link Object} in an arbitrary-order
* {@code Object} array.
*
* @param values
* an array of {@code Object}s with arbitrary order.
* @param a
* the equivalent {@code Object} to search for. May be
* {@code null}.
* @return the lowest index of any element in {@code values} such that
* {@code Java7.equals(a, values[i])}, or {@code -1} otherwise.
*/
public static int indexOf(Object[] values, Object a) {
for (int i = 0; i < values.length; i++) {
if (Java7.Objects.equals(a, values[i])) {
return i;
}
}
return -1;
}
public static <T> int indexOf(T[] array, Predicate<T> predicate) {
for (int i = 0; i < array.length; i++) {
if (predicate.test(array[i])) {
return i;
}
}
return -1;
}
public static String join(String delimiter, Object... expected) {
if (expected.length == 0) {
return "";
}
StringBuilder sb = new StringBuilder(expected[0].toString());
for (int i = 1; i < expected.length; i++) {
sb.append(delimiter).append(expected[i]);
}
return sb.toString();
}
public static <I, O> O[] map(I[] in, O[] out, Function<I, O> function) {
for (int i = 0; i < out.length; i++) {
out[i] = function.apply(in[i]);
}
return out;
}
public static int max(int[] values) {
int max = Integer.MIN_VALUE;
for (final int value : values) {
max = Math.max(max, value);
}
return max;
}
public static String prettyPrint(double[] a, int columns, int start, int end, int newlineInterval,
String elemFormat) {
StringBuffer sb = new StringBuffer();
int indexWidth = (int) Math.log10(a.length) + 1;
String indexFormat = "%" + indexWidth + "d";
int rows = 0;
int i = start;
while (i < end) {
if (i > start) {
sb.append('\n');
}
sb.append('[').append(String.format(indexFormat, i)).append("] ");
for (int col = 0; col < columns && i < end; col++, i++) {
if (col > 0) {
sb.append(" ");
}
sb.append(String.format(elemFormat, a[i]));
}
if (++rows == newlineInterval) {
rows = 0;
sb.append('\n');
}
}
return sb.toString();
}
public static String prettyPrint(double[][] a, String elemFormat) {
StringBuffer sb = new StringBuffer();
int indexWidth = (int) Math.log10(a.length) + 1;
String indexFormat = "%" + indexWidth + "d";
for (int row = 0; row < a.length; row++) {
sb.append('[').append(String.format(indexFormat, row)).append("] ");
for (int col = 0; col < a[row].length; col++) {
sb.append(String.format(elemFormat, a[row][col])).append(" ");
}
sb.append('\n');
}
return sb.toString();
}
public static String prettyPrint(float[] a, int columns) {
int intDigits = 0;
int fracDigits = 0;
for (float f : a) {
if (f == 0f) {
continue;
}
int log = (int) Math.floor(Math.log10(Math.abs(f)));
intDigits = Math.max(intDigits, log + 1);
fracDigits = Math.max(fracDigits, -log);
}
String elemFormat = String.format("%%%d.%df", intDigits + fracDigits + 2, fracDigits);
return prettyPrint(a, columns, 0, a.length, 0, elemFormat);
}
public static String prettyPrint(float[] a, int columns, int start, int end, int newlineInterval,
String elemFormat) {
StringBuffer sb = new StringBuffer();
int indexWidth = (int) Math.log10(a.length) + 1;
String indexFormat = "%" + indexWidth + "d";
int rows = 0;
int i = start;
while (i < end) {
sb.append('[').append(String.format(indexFormat, i)).append("] ");
for (int col = 0; col < columns - 1 && i < end; col++, i++) {
sb.append(String.format(elemFormat, a[i])).append(" ");
}
if (i < end) {
sb.append(String.format(elemFormat, a[i++])).append('\n');
}
if (++rows == newlineInterval) {
rows = 0;
sb.append('\n');
}
}
return sb.toString();
}
public static String prettyPrint(float[][] a, String elemFormat) {
StringBuffer sb = new StringBuffer();
int indexWidth = (int) Math.log10(a.length) + 1;
String indexFormat = "%" + indexWidth + "d";
for (int row = 0; row < a.length; row++) {
sb.append('[').append(String.format(indexFormat, row)).append("] ");
for (int col = 0; col < a[row].length; col++) {
sb.append(String.format(elemFormat, a[row][col])).append(" ");
}
sb.append('\n');
}
return sb.toString();
}
public static String prettyPrint(int[] a, int columns, int start, int end, int newlineInterval, String elemFormat) {
StringBuffer sb = new StringBuffer();
int indexWidth = (int) Math.log10(a.length) + 1;
String indexFormat = "%" + indexWidth + "d";
int rows = 0;
int i = start;
while (i < end) {
sb.append('[').append(String.format(indexFormat, i)).append("] ");
for (int col = 0; col < columns - 1 && i < end; col++, i++) {
sb.append(String.format(elemFormat, a[i])).append(" ");
}
if (i < end) {
sb.append(String.format(elemFormat, a[i++])).append('\n');
}
if (++rows == newlineInterval) {
rows = 0;
sb.append('\n');
}
}
return sb.toString();
}
public static String prettyPrintAsNumbers(char[] a, int columns, int start, int end, int newlineInterval,
String elemFormat) {
StringBuffer sb = new StringBuffer();
int indexWidth = (int) Math.log10(a.length) + 1;
String indexFormat = "%" + indexWidth + "d";
int rows = 0;
int i = start;
while (i < end) {
sb.append('[').append(String.format(indexFormat, i)).append("] ");
for (int col = 0; col < columns - 1 && i < end; col++, i++) {
sb.append(String.format(elemFormat, (int) a[i])).append(" ");
}
if (i < end) {
sb.append(String.format(elemFormat, (int) a[i++])).append('\n');
}
if (++rows == newlineInterval) {
rows = 0;
sb.append('\n');
}
}
return sb.toString();
}
/**
* Finds the first index of {@link Object} in an arbitrary-order
* {@code Object} array.
*
* @param values
* an array of {@code Object}s with arbitrary order.
* @param a
* the {@code Object} to search for. May be {@code null}.
* @return the lowest index of {@code a} in {@code values}, or {@code -1} if
* it is not present.
*/
public static int strictIndexOf(Object[] values, Object a) {
for (int i = 0; i < values.length; i++) {
if (a == values[i]) {
return i;
}
}
return -1;
}
/**
* Swaps two elements in an array.
*
* @param a
* the array to swap elements of.
* @param i0
* the index of the first element.
* @param i1
* the index of the second element.
*/
public static void swap(double[] a, int i0, int i1) {
double temp = a[i0];
a[i0] = a[i1];
a[i1] = a[i0];
}
public static <O, T extends Throwable> O[] throwableMap(double[] in, O[] out, ThrowingDoubleFunction<O, T> function)
throws T {
for (int i = 0; i < out.length; i++) {
out[i] = function.apply(in[i]);
}
return out;
}
public static <I, T extends Throwable> double[] throwableMap(I[] in, double[] out,
ThrowingToDoubleFunction<I, T> function) throws T {
for (int i = 0; i < out.length; i++) {
out[i] = function.applyAsDouble(in[i]);
}
return out;
}
public static <I, O, T extends Throwable> O[] throwableMap(I[] in, O[] out, ThrowingFunction<I, O, T> function)
throws T {
for (int i = 0; i < out.length; i++) {
out[i] = function.apply(in[i]);
}
return out;
}
public static <T> T[] toArray(Iterable<? extends T> iterable, Class<T> componentType) {
int count = 0;
for (T t : iterable) {
count++;
}
T[] result = (T[]) Array.newInstance(componentType, count);
int k = 0;
for (T t : iterable) {
result[k++] = t;
}
return result;
}
public static ArrayList<Double> toArrayList(double[] values) {
ArrayList<Double> result = new ArrayList<Double>();
for (double value : values) {
result.add(value);
}
return result;
}
public static ArrayList<Float> toArrayList(float[] values) {
ArrayList<Float> result = new ArrayList<Float>();
for (float value : values) {
result.add(value);
}
return result;
}
public static double[] toDoubleArray(Collection<Double> doubles) {
double[] result = new double[doubles.size()];
int k = 0;
for (Double d : doubles) {
result[k++] = d;
}
return result;
}
public static float[] toFloatArray(Collection<Float> floats) {
float[] result = new float[floats.size()];
int k = 0;
for (Float d : floats) {
result[k++] = d;
}
return result;
}
public static float[] toFloatArray2(Collection<Number> numbers) {
float[] result = new float[numbers.size()];
int k = 0;
for (Number d : numbers) {
result[k++] = d.floatValue();
}
return result;
}
public static int[] toIntArray(Collection<Integer> ints) {
int[] result = new int[ints.size()];
int k = 0;
for (int d : ints) {
result[k++] = d;
}
return result;
}
public static double[] toSortedDoubleArray(Collection<Double> doubles) {
double[] result = toDoubleArray(doubles);
Arrays.sort(result);
return result;
}
public static int[] toSortedIntArray(Collection<Integer> ints) {
int[] result = toIntArray(ints);
Arrays.sort(result);
return result;
}
private ArrayUtils() {
}
}