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

org.chocosolver.util.tools.ArrayUtils Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2024, IMT Atlantique. All rights reserved.
 *
 * Licensed under the BSD 4-clause license.
 *
 * See LICENSE file in the project root for full license information.
 */
package org.chocosolver.util.tools;

import gnu.trove.list.array.TIntArrayList;
import org.chocosolver.solver.variables.BoolVar;
import org.chocosolver.solver.variables.IntVar;

import java.util.*;

import static java.lang.reflect.Array.newInstance;

/**
 * This class contains various methods for manipulating arrays.
 * 
* * @author Charles Prud'homme, Jean-Guillaume Fages, Rene Helmke * @since 17 sept. 2010 */ public enum ArrayUtils { ; /** * Creates an array of ints of consecutive values from lb (inclusive) to ub (inclusive as well), * i.e. the range [lb, ub], * For instance: {3,4,...,99,100} * * @param lb first element in the array * @param ub last element in the array * @return an array of ints * @throws NegativeArraySizeException if ubc extracted from matrix array. * * @param array double entry matrix * @param c index of the column to get * @return the column c from array, or null if array is null or array.length is null, * or if c is negative or if array.length < c */ @SuppressWarnings({"unchecked", "RedundantCast"}) public static int[] getColumn(final int[][] array, final int c) { if (array != null && array.length > 0 && c >= 0 && array[0].length > c) { int[] res = new int[array.length]; for (int i = 0; i < array.length; i++) { res[i] = array[i][c]; } return res; } return null; } /** * Returns the column c extracted from matrix array. * * @param array double entry matrix * @param c index of the column to get * @return the column c from array, or null if array is null or array.length is null, * or if c is negative or if array.length < c */ @SuppressWarnings({"unchecked", "RedundantCast"}) public static double[] getColumn(final double[][] array, final int c) { if (array != null && array.length > 0 && c >= 0 && array[0].length > c) { double[] res = new double[array.length]; for (int i = 0; i < array.length; i++) { res[i] = array[i][c]; } return res; } return null; } /** * Returns the column c extracted from matrix array. * * @param array double entry matrix * @param c index of the column to get * @param the class of the objects in the input matrix * @return the column c from array, or null if array is null or array.length is null, * or if c is negative or if array.length < c */ @SuppressWarnings({"unchecked", "RedundantCast"}) public static T[] getColumn(final T[][] array, final int c) { return getColumn(array, c, (Class) array[0].getClass()); } /** * Returns the column c extracted from matrix array. * * @param array double entry matrix * @param c index of the column to get * @param newType the class of the copy to be returned * @param the class of the objects in the input matrix * @return the column c from array, or null if array is null or array.length is null, * or if c is negative or if array.length < c */ @SuppressWarnings({"unchecked", "RedundantCast"}) public static T[] getColumn(final T[][] array, final int c, Class newType) { if (array != null && array.length > 0 && c >= 0 && array[0].length > c) { T[] res = ((Object) newType == (Object) Object[].class) ? (T[]) new Object[array.length] : (T[]) newInstance(newType.getComponentType(), array.length); for (int i = 0; i < array.length; i++) { res[i] = (T) array[i][c]; } return res; } return null; } /** * Sum the lengths of arrays * * @param arrays list of arrays * @param the class of the objects in the input array * @return the sum of lengths of arrays */ @SafeVarargs public static int length(final T[]... arrays) { int length = 0; for (T[] array : arrays) { if (array != null) length += array.length; } return length; } /** * @param array array of elements * @param obj element to find * @param the class of the objects in the input array * @return true if array contains obj */ public static boolean contains(T[] array, T obj) { for (T elem : array) { if (elem.equals(obj)) return true; } return false; } /** * Returns the element in position index when considering all arrays appended altogether. * * @param index position of the element to return * @param arrays list of arrays * @param the class of the objects in the input arrays * @return the element in position index when considering all arrays appended altogether. */ @SafeVarargs public static T get(int index, final T[]... arrays) { int shift = index; for (T[] tab : arrays) { if (shift < tab.length) { return tab[shift]; } else { shift -= tab.length; } } return null; } /** * Returns the element in position index when considering all arrays appended altogether. * * @param index position of the element to return * @param arrays list of arrays * @param the class of the objects in the input lists * @return the element in position index when considering all arrays appended altogether. */ @SafeVarargs public static T get(int index, final List... arrays) { int shift = index; for (List tab : arrays) { if (shift < tab.size()) { return tab.get(shift); } else { shift -= tab.size(); } } return null; } /** * Append two Arrays * * @param toAppend array of arrays to append * @return a new Array composed of both given in parameters. */ @SuppressWarnings("unchecked") public static T[] append(T[]... toAppend) { int total = length(toAppend); T[] ret = (T[]) newInstance(toAppend.getClass().getComponentType().getComponentType(), total); int pos = 0; for (T[] tab : toAppend) { if (tab != null) { System.arraycopy(tab, 0, ret, pos, tab.length); pos += tab.length; } } return ret; } /** * Append two Arrays * * @param toAppend array of arrays to append * @return a new Array composed of both given in parameters. */ public static IntVar[] append(IntVar[]... toAppend) { int total = length(toAppend); IntVar[] ret = new IntVar[total]; int pos = 0; for (IntVar[] tab : toAppend) { if (tab != null) { System.arraycopy(tab, 0, ret, pos, tab.length); pos += tab.length; } } return ret; } /** * Append two Arrays * * @param toAppend array of arrays to append * @return a new Array composed of both given in parameters. */ public static BoolVar[] append(BoolVar[]... toAppend) { int total = length(toAppend); BoolVar[] ret = new BoolVar[total]; int pos = 0; for (BoolVar[] tab : toAppend) { if (tab != null) { System.arraycopy(tab, 0, ret, pos, tab.length); pos += tab.length; } } return ret; } /** * Append elements at the end of another array * * @param array array of arrays to append * @param elements elements to append * @return a new Array composed of both given in parameters. */ @SuppressWarnings("unchecked") public static T[] concat(T[] array, T... elements) { return append(array, elements); } /** * Append elements at the end of another array * * @param array array of arrays to append * @param elements elements to append * @return a new Array composed of both given in parameters. */ public static IntVar[] concat(IntVar[] array, IntVar... elements) { return append(array, elements); } /** * Append elements at the end of another array * * @param array array of arrays to append * @param elements elements to append * @return a new Array composed of both given in parameters. */ public static BoolVar[] concat(BoolVar[] array, BoolVar... elements) { return append(array, elements); } /** * Append int arrays * * @param toAppend array of arrays to append * @return a new Array composed of those given in parameters. */ public static int[] append(int[]... toAppend) { int total = 0; for (int[] tab : toAppend) { if (tab != null) { total += tab.length; } } int[] ret = new int[total]; int pos = 0; for (int[] tab : toAppend) { if (tab != null) { System.arraycopy(tab, 0, ret, pos, tab.length); pos += tab.length; } } return ret; } /** * Append elements at the end of another array * * @param array array of arrays to append * @param elements elements to append * @return a new Array composed of both given in parameters. */ public static int[] concat(int[] array, int... elements) { return append(array, elements); } /** * Reverse all signs of the a given int table. * * @param tab array to inverse */ public static void inverseSign(int[] tab) { for (int i = 0; i < tab.length; i++) { tab[i] = -tab[i]; } } /** * Turns back to from the elements of tab from the middle position. * * @param tab array to reverse */ public static void reverse(int[] tab) { int tmp; final int n = tab.length; for (int i = 0; i < n / 2; i++) { tmp = tab[i]; tab[i] = tab[n - i - 1]; tab[n - i - 1] = tmp; } } /** * Turns back to from the elements of tab from the middle position. * * @param tab array to reverse * @param the class of the objects in the input array */ public static void reverse(T[] tab) { T tmp; final int n = tab.length - 1; for (int i = 0; i <= n / 2; i++) { tmp = tab[i]; tab[i] = tab[n - i]; tab[n - i] = tmp; } } /** * Permutes elements from tab wrt to permutuation: tab[i] = tab[permutation[i]]. * * @param permutation permutation * @param tab array of ints * @param the class of the objects in the input array */ public static void permutation(int[] permutation, T[] tab) { T[] tmp = tab.clone(); for (int i = 0; i < tab.length; i++) { tab[i] = tmp[permutation[i]]; } } /** * Returns a list composed of elements from array. * * @param array array of elements * @param the class of the objects in the input array * @return a list composed of elements from array. */ public static List toList(T[] array) { return Arrays.asList(array); } /** * Returns an array composed of elements from list. * * @param c the class of the copy to be returned * @param list list of elements * @param the class of the objects in the input array * @return an array composed of elements from list. */ @SuppressWarnings("unchecked") public static T[] toArray(Class c, List list) { // T[] array = (T[])Array.newInstance(c, list.size()); // return list.toArray(array); return list.toArray((T[]) newInstance(c, list.size())); } /** * Creates an array from vargs elt. * * @param elt elements to put in an array * @param the class of the objects in the returned array * @return an array from vargs elt */ @SafeVarargs public static T[] toArray(T... elt) { return elt; } /** * Creates an array from elements in list. * * @param list elements to put in an array * @param the class of the objects in the returned array * @return an array from element in list */ public static T[] toArray(List list) { return toArray(list.get(0).getClass(), list); } /** * Transposes a matrix M[n][m] in a matrix MT[m][n] such that MT[i][j] = M[j][i] * * @param matrix matrix to transpose * @param the class of the objects in the input matrix * @return a matrix */ @SuppressWarnings("unchecked") public static T[][] transpose(T[][] matrix) { T[][] ret = (T[][]) newInstance(matrix.getClass().getComponentType(), matrix[0].length); for (int i = 0; i < ret.length; i++) { ret[i] = (T[]) newInstance(matrix[0].getClass().getComponentType(), matrix.length); } for (int i = 0; i < matrix.length; i++) for (int j = 0; j < matrix[i].length; j++) ret[j][i] = matrix[i][j]; return ret; } /** * Transposes a matrix M[n][m] in a matrix MT[m][n] such that MT[i][j] = M[j][i] * * @param matrix matrix to transpose * @return a matrix */ public static int[][] transpose(int[][] matrix) { int[][] ret = (int[][]) newInstance(matrix.getClass().getComponentType(), matrix[0].length); for (int i = 0; i < ret.length; i++) { ret[i] = (int[]) newInstance(matrix[0].getClass().getComponentType(), matrix.length); } for (int i = 0; i < matrix.length; i++) for (int j = 0; j < matrix[i].length; j++) ret[j][i] = matrix[i][j]; return ret; } /** * Flattens a matrix M[n][m] in an array F[n*m] such that F[i*n+j] = M[i][j]. * * @param matrix matrix to flatten * @param the class of the objects in the input matrix * @return a matrix */ @SuppressWarnings("unchecked") public static T[] flatten(T[][] matrix) { int sz = 0; for (T[] t : matrix) sz += t.length; T[] ret = (T[]) newInstance(matrix[0].getClass().getComponentType(), sz); int k = 0; for (T[] ta : matrix) { for (T t : ta) ret[k++] = t; } return ret; } /** * Flattens a matrix M[n][m][p] in an array F[n*m*p] such that F[(i*n*m) + (j*m) + k] = M[i][j][k]. * * @param matrix matrix to flatten * @param the class of the objects in the input matrix * @return a matrix */ @SuppressWarnings("unchecked") public static T[] flatten(T[][][] matrix) { List elt = new ArrayList<>(); for (T[][] t : matrix) { for (T[] tt : t) { elt.addAll(Arrays.asList(tt)); } } T[] ret = (T[]) newInstance(matrix[0][0].getClass().getComponentType(), elt.size()); return elt.toArray(ret); } @SuppressWarnings("unchecked") public static T[] flattenSubMatrix(int iMin, int iLength, int jMin, int jLength, T[][] matrix) { T[] ret = (T[]) newInstance(matrix[0].getClass().getComponentType(), iLength * jLength); for (int i = 0, k = 0; i < iLength; i++, k += jLength) System.arraycopy(matrix[iMin + i], jMin, ret, k, jLength); return ret; } /** * Flattens a matrix M[n][m] in an array F[n*m] such that F[i*n+j] = M[i][j]. * * @param matrix matrix to flatten * @return a matrix */ public static int[] flatten(int[][] matrix) { int sz = 0; for (int[] t : matrix) sz += t.length; final int[] ret = new int[sz]; int k = 0; for (int[] ta : matrix) { for (int t : ta) ret[k++] = t; } return ret; } public static int[] createNonRedundantSortedValues(TIntArrayList values) { values.sort(); int offset = 1; while (offset < values.size()) { while (values.get(offset - 1) == values.get(offset)) { values.remove(offset); if (offset == values.size()) { break; } } offset++; } return values.toArray(); } /** * Create an array of elements in set and sort them using {@link Arrays#sort(Object[])} * * @param set set of elements * @param the class of the objects in the input set. * @return an array of sorted elements from set */ @SuppressWarnings("unchecked") public static > T[] sort(Set set) { final LinkedList tmpl = new LinkedList<>(set); if (tmpl.isEmpty()) { return null; } else { T[] tmpa = (T[]) newInstance(tmpl.getFirst().getClass(), tmpl.size()); tmpl.toArray(tmpa); Arrays.sort(tmpa); return tmpa; } } /** * Duplicates arr and returns the new copy * * @param arr matrix to duplicate * @return a copy of arr */ public static int[][][][] swallowCopy(int[][][][] arr) { int s0 = arr.length; int[][][][] copy = new int[s0][][][]; for (int i = s0 - 1; i >= 0; i--) { int s1 = arr[i].length; copy[i] = new int[s1][][]; for (int j = s1 - 1; j >= 0; j--) { int s2 = arr[i][j].length; copy[i][j] = new int[s2][]; for (int k = s2 - 1; k >= 0; k--) { int s3 = arr[i][j][k].length; copy[i][j][k] = new int[s3]; System.arraycopy(arr[i][j][k], 0, copy[i][j][k], 0, s3); } } } return copy; } /** * Duplicates arr and returns the new copy * * @param arr matrix to duplicate * @return a copy of arr */ public static int[][][] swallowCopy(int[][][] arr) { int s0 = arr.length; int[][][] copy = new int[s0][][]; for (int i = s0 - 1; i >= 0; i--) { int s1 = arr[i].length; copy[i] = new int[s1][]; for (int j = s1 - 1; j >= 0; j--) { int s2 = arr[i][j].length; copy[i][j] = new int[s2]; System.arraycopy(arr[i][j], 0, copy[i][j], 0, s2); } } return copy; } /** * Creates and returns an array of ints composed of unique values from 0 (inclusive) to nb (exclusive), in random order. * * @param nb upper value (exclusive) * @return an array of ints composed of unique values from 0 (inclusive) to nb (exclusive), in random order. */ public static int[] zeroToNShuffle(int nb) { return zeroToNShuffle(nb, System.nanoTime()); } /** * Creates and returns an array of ints composed of unique values from 0 (inclusive) to nb (exclusive), in random order. * * @param nb upper value (exclusive) * @param seed seed for randomness * @return an array of ints composed of unique values from 0 (inclusive) to nb (exclusive), in random order. */ public static int[] zeroToNShuffle(int nb, long seed) { Random r = new Random(seed); int[] ret = new int[nb]; ArrayList tmp = new ArrayList<>(); for (int i = 0; i < nb; i++) tmp.add(i); Collections.shuffle(tmp); return tmp.stream().mapToInt(i -> i).toArray(); } /** * Permutes randomly elements from tab * * @param tab array of ints * @param r randomness generator */ public static void randomPermutations(int[] tab, Random r) { int l = tab.length; for (int i = 0; i < l; i++) { int j = r.nextInt(l); int tmp = tab[i]; tab[i] = tab[j]; tab[j] = tmp; } } /** * Permutes randomly elements from tab * * @param tab array of ints * @param seed seed for randomness */ public static void randomPermutations(int[] tab, long seed) { randomPermutations(tab, new Random(seed)); } /** * Permutes randomly elements from tab * * @param tab array of ints * @param r randomness generator * @param the class of the objects in the input array */ public static void randomPermutations(E[] tab, Random r) { int l = tab.length; for (int i = 0; i < l; i++) { int j = r.nextInt(l); E tmp = tab[i]; tab[i] = tab[j]; tab[j] = tmp; } } /** * Permutes randomly elements from tab * * @param tab array of ints * @param seed seed for randomness * @param the class of the objects in the input array */ public static void randomPermutations(E[] tab, long seed) { randomPermutations(tab, new Random(seed)); } /** * Adapted from java.util.Arrays#binarySearch0(int[], int, int, int) , * it returns the value greater or equal to key in an increasing order value array * If the key exists in a, it returns the index of key in a, * otherwise it returns the index of the closest value greater than key when gq is set to true, * or the index of the closest value smaller than key when gq is set to false. * * @param a the values, increasingly ordered * @param fromIndex starting index (inclusive) * @param toIndex ending index (exclusive) * @param key value to look for * @param gq set to true to look for the value greater or equal to key, * false to look for the value smaller or equal to the key */ public static int binarySearchInc(int[] a, int fromIndex, int toIndex, int key, boolean gq) { int p = Arrays.binarySearch(a, fromIndex, toIndex, key); if (p >= 0) { return p; } else { p = -(p + 1); p -= (gq ? 0 : 1); return p; } } /** * Sorts the input array if it is not already sorted, * and removes multiple occurrences of the same value * * @param values array of values * @return a sorted array containing each value of values exactly once */ public static int[] mergeAndSortIfNot(int[] values) { int n = values.length; boolean sorted = true; boolean noDouble = true; for (int i = 0; i < n - 1 && sorted; i++) { if (values[i] > values[i + 1]) { sorted = false; noDouble = false;// cannot be sure } if (values[i] == values[i + 1]) { noDouble = false; } } if (!sorted) { Arrays.sort(values); } if (!noDouble) { int nbVals = 1; for (int i = 0; i < n - 1; i++) { assert values[i] <= values[i + 1]; if (values[i] < values[i + 1]) { nbVals++; } } if (nbVals < n) { int[] correctValues = new int[nbVals]; int idx = 0; for (int i = 0; i < n - 1; i++) { if (values[i] < values[i + 1]) { correctValues[idx++] = values[i]; } } correctValues[idx] = values[n - 1]; return correctValues; } } return values; } /** * Compute a new size, classically for array. * The new size is at least increased by 1 and at most by `max`. * * @param curSize the current size * @return the new size */ public static int newBoundedSize(int curSize, int max) { return curSize + Math.max(1, Math.min(max, (curSize >> 1))); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy