/*******************************************************************************
* Copyright (c) 2007 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial implementation
*******************************************************************************/
package melnorme.utilbox.misc;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import static melnorme.utilbox.core.CoreUtil.areEqual;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import melnorme.utilbox.collections.Collection2;
import java.util.function.Function;
import java.util.function.Predicate;
public class ArrayUtil {
public static final Object[] EMPTY_ARRAY = new Object[] {};
/** @return the given array if it is non-null, an empty array otherwise. */
public static Object[] nullToEmpty(Object[] array) {
return array == null ? EMPTY_ARRAY : array;
}
/** @return the given array if it is non-null, an empty array otherwise with given componentType. */
public static <T> T[] nullToEmpty(T[] array, Class<T> componentType) {
return array == null ? create(0, componentType) : array;
}
@SuppressWarnings("unchecked")
public static <T> T[] create(int length, Class<T> componentType) {
return (T[]) Array.newInstance(componentType, length);
}
@SuppressWarnings("unchecked")
public static <T> T[] create(Class<T> componentType, int length) {
return (T[]) Array.newInstance(componentType, length);
}
/** Creates a new array of given length, and same component type as given similarArray. */
@SuppressWarnings("unchecked")
public static <T> T[] createWithSameComponentType(int length, T[] similarArray) {
return (T[]) Array.newInstance(similarArray.getClass().getComponentType(), length);
}
/** Create an array from the given element, with the given componentType.
* If the element is null, a zero-length array is created. */
public static <T> T[] singletonArray(T element, Class<T> componentType) {
if(element == null) {
return create(componentType, 0);
}
T[] newArray = create(componentType, 1);
newArray[0] = element;
return newArray;
}
/** Create an array from the given list, with the given componentType.
* If given list is null, a zero-length array is created. */
public static <T> T[] createFrom(Collection<? extends T> list, Class<T> componentType) {
if(list == null) {
return create(componentType, 0);
}
return list.toArray(create(componentType, list.size()));
}
/** Create an array from the given list, with Object.class as the component type.
* If given list is null, a zero-length array is created. */
public static Object[] createFrom(Collection<?> list) {
return createFrom(list, Object.class);
}
public static <E> E[] copyFrom(E[] array, Class<E> componentType) {
E[] newArray = create(array.length, componentType);
System.arraycopy(array, 0, newArray, 0, array.length);
return newArray;
}
/** Create an array from the given list, with the given cpType as the run-time component type.
* If the list is null, null is returned. */
public static <T> T[] toArray(Collection<? extends T> list, Class<T> componentType) {
if(list == null) {
return null;
}
return list.toArray(create(componentType, list.size()));
}
/** Creates a new array with the given length, and of the same type as the given array. */
public static <T> T[] copyFrom(T[] array, int newLength) {
T[] copy = createWithSameComponentType(newLength, array);
System.arraycopy(array, 0, copy, 0, Math.min(array.length, newLength));
return copy;
}
/** Creates a copy of given array with the given newlength, and of type char[]. */
public static char[] copyFrom(char[] array, int newLength) {
char[] copy = (char[]) Array.newInstance(Character.TYPE, newLength);
System.arraycopy(array, 0, copy, 0, Math.min(array.length, newLength));
return copy;
}
/** Creates a copy of given array with the given newlength, and of type byte[]. */
public static byte[] copyFrom(byte[] array, int newLength) {
byte[] copy = (byte[]) Array.newInstance(Byte.TYPE, newLength);
System.arraycopy(array, 0, copy, 0, Math.min(array.length, newLength));
return copy;
}
/** Creates a copy of given array with the given newlength, and of type int[]. */
public static int[] copyFrom(int[] array, int newLength) {
int[] copy = (int[]) Array.newInstance(Integer.TYPE, newLength);
System.arraycopy(array, 0, copy, 0, Math.min(array.length, newLength));
return copy;
}
/** Creates a copy of given array, and of type int[]. */
public static int[] copyFrom(int[] array) {
return copyFrom(array, array.length);
}
/** Creates a copy of given array, and of type T[]. */
public static <T> T[] copyFrom(T[] array) {
return Arrays.copyOf(array, array.length);
}
/** Same as {@link Arrays#copyOfRange(Object[], int, int)} */
public static <T> T[] copyOfRange(T[] original, int from, int to) {
return Arrays.copyOfRange(original, from, to);
}
/** Same as {@link Arrays#copyOfRange(Object[], int, int, Class)} */
public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
return Arrays.copyOfRange(original, from, to, newType);
}
/** Creates an int[] from given coll of Integers. */
public static int[] createIntArray(List<? extends Integer> coll) {
int[] array = new int[coll.size()];
for (int i = 0; i < coll.size(); i++) {
array[i] = coll.get(i);
}
return array;
}
/** Creates an array with the same size as the given list.
* If the list is null, a zero-length array is created. */
public static <T> T[] newSameSize(List<?> list, Class<T> cpType) {
if(list == null)
return create(cpType, 0);
else
return create(cpType, list.size());
}
/** Copies src array range [0 .. src.length] to dest array starting at destIx. */
public static void copyToRange(byte[] src, byte[] dest, int destIx) {
assertTrue(src.length < dest.length - destIx);
System.arraycopy(src, 0, dest, destIx, src.length);
}
/** Appends an element to array, creating a new array. */
public static <T> T[] append(T[] base, T element) {
T[] newArray = copyFrom(base, base.length + 1);
newArray[base.length] = element;
return newArray;
}
/** Creates a new array with given first element prepended to given rest array. */
@SafeVarargs
public static <T> T[] prepend(T first, T... rest) {
T[] newArray = createWithSameComponentType(rest.length + 1, rest);
newArray[0] = first;
System.arraycopy(rest, 0, newArray, 1, rest.length);
return newArray;
}
/** Appends given array other to given array base,
* creating a new array of the same runtime type as original. */
@SafeVarargs
public static <T> T[] concat(T[] base, T... other) {
return concat(base, other, other.length);
}
/** Appends appendCount number of elements of given array other to given array base,
* creating a new array of the same runtime type as original. */
public static <T> T[] concat(T[] base, T[] other, int appendCount) {
T[] newArray = copyFrom(base, base.length + appendCount);
System.arraycopy(other, 0, newArray, base.length, appendCount);
return newArray;
}
/** Appends appendCount number of elements of given array other to given array base */
public static byte[] concat(byte[] base, byte[] other, int appendCount) {
final int length = base.length;
byte[] newArray = copyFrom(base, base.length + appendCount);
System.arraycopy(other, 0, newArray, length, appendCount);
return newArray;
}
/** Appends appendCount number of elements of given array other to given array base */
public static char[] concat(char[] base, char[] other, int appendCount) {
final int length = base.length;
char[] newArray = copyFrom(base, base.length + appendCount);
System.arraycopy(other, 0, newArray, length, appendCount);
return newArray;
}
/** Removes from the given array the first element that isEqual to given objToRemove. */
public static<T> T[] remove(T[] array, T objToRemove) {
for (int i = 0; i < array.length; i++) {
T elem = array[i];
if(areEqual(elem, objToRemove))
return removeAt(array, i);
}
return array;
}
/** Removes the element at index ix from array, creating a new array. */
public static <T> T[] removeAt(T[] array, int ix) {
T[] newArray = copyFrom(array, array.length - 1);
System.arraycopy(array, 0, newArray, 0, ix);
System.arraycopy(array, ix + 1, newArray, ix, array.length - ix - 1);
return newArray;
}
/** Removes the last given count elements from given array, creating a new array. */
public static <T> T[] removeLast(T[] array, int count) {
assertTrue(array.length >= count);
T[] newArray = ArrayUtil.copyFrom(array, array.length - count);
return newArray;
}
/** Removes from the given array the first element that areEqual given objToRemove.
* @return a new array with elements removed, or the same array if no elements where removed. */
public static<T> T[] removeAll(T[] array, T objToRemove) {
int removeCount = 0;
for (T elem : array) {
if(areEqual(elem, objToRemove)) {
removeCount++;
}
}
if(removeCount == 0) {
return array;
}
int ix = 0;
T[] newArray = createWithSameComponentType(array.length - removeCount, array);
for (T elem : array) {
if(areEqual(elem, objToRemove)) {
continue;
}
newArray[ix] = elem;
ix++;
}
return newArray;
}
/* ====================== search/index ====================== */
/** @return the last element of given array, or null if array is empty. */
public static <T> T getLastElement(T[] array) {
if(array.length == 0) {
return null;
}
return array[array.length-1];
}
/** @return the same as {@link List#indexOf(Object)}, using given array as a collection. */
public static <T> int indexOf(T[] array, T elem) {
// return Arrays.asList(array).indexOf(elem);
if(elem == null) {
for(int ix = 0; ix < array.length; ix++) {
if(array[ix] == null)
return ix;
}
} else {
for(int ix = 0; ix < array.length; ix++) {
if(elem.equals(array[ix]))
return ix;
}
}
return -1;
}
/** @return true if array contains an element equal to obj. */
public static <T> boolean contains(T[] array, T obj) {
return indexOf(array, obj) != -1;
}
/** @return the index in given array of the first occurrence of given elem, or -1 if none is found. */
public static int indexOf(byte[] array, byte elem) {
for (int i = 0; i < array.length; i++) {
if(array[i] == elem)
return i;
}
return -1;
}
public static int indexOf(char[] array, char elem) {
for (int i = 0; i < array.length; i++) {
if(array[i] == elem)
return i;
}
return -1;
}
/** @return the index in given array of the first element that is the same as given elem,
* or -1 if none is found. */
public static <T> int indexOfIdentity(T[] array, T elem) {
for (int i = 0; i < array.length; i++) {
if(array[i] == elem)
return i;
}
return -1;
}
/** @return true if array contains an element that matched given predicate. */
public static <T> boolean search(T[] array, Predicate<T> predicate) {
for(T elem: array) {
if(predicate.test(elem))
return true;
}
return false;
}
/** Is {@link #map(Object[], Function, Class)} with klass = Object.class */
public static <T> Object[] map(T[] array, Function<? super T, ? extends Object> evalFunction) {
return ArrayUtil.map(array, evalFunction, Object.class);
}
/** Creates a new array, based on given array, whose elements are produced element-wise from the original
* array using given evalFunction. */
public static <T, R> R[] map(T[] array, Function<? super T, ? extends R> evalFunction, Class<R> klass) {
R[] newArray = create(array.length, klass);
for(int i = 0; i < newArray.length; i++) {
newArray[i] = evalFunction.apply(array[i]);
}
return newArray;
}
/** Is {@link #map(Collection, IEvalFunc, Class klass)}, IEvalFunc, Class) with klass = Object.class */
public static <T> Object[] map(Collection<T> coll, Function<? super T, ? extends Object> evalFunction) {
return map(coll, evalFunction, Object.class);
}
/** Is {@link #map(Collection, IEvalFunc, Class klass)}, IEvalFunc, Class) with klass = Object.class */
public static <T> Object[] map(Collection2<T> coll, Function<? super T, ? extends Object> evalFunction) {
return map(coll, evalFunction, Object.class);
}
/** Creates a new array, based on given coll, whose elements are produced element-wise from the original
* coll using given evalFunction. */
public static <T, R> R[] map(Collection<T> coll, Function<? super T, ? extends R> evalFunction, Class<R> klass) {
R[] newArray = create(coll.size(), klass);
int i = 0;
for(T elem : coll) {
newArray[i] = evalFunction.apply(elem);
i++;
}
return newArray;
}
/** Creates a new array, based on given coll, whose elements are produced element-wise from the original
* coll using given evalFunction. */
public static <T, R> R[] map(Collection2<T> coll, Function<? super T, ? extends R> evalFunction, Class<R> klass) {
R[] newArray = create(coll.size(), klass);
int i = 0;
for(T elem : coll) {
newArray[i] = evalFunction.apply(elem);
i++;
}
return newArray;
}
/** Filters given array, using given predicate, creating a new array. */
public static <T> T[] filter(T[] array, Predicate<T> predicate) {
T[] newArray = createWithSameComponentType(array.length, array);
assertTrue(newArray.length <= array.length);
int newIx = 0, arrayIx = 0;
while(arrayIx < array.length) {
if(predicate.test(array[arrayIx])) {
newArray[newIx] = array[arrayIx];
newIx++; arrayIx++;
} else {
arrayIx++;
}
}
return newIx == arrayIx ? newArray : Arrays.copyOfRange(newArray, 0, newIx);
}
}