package vroom.common.utilities;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.AbstractList;
import java.util.AbstractSequentialList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import umontreal.iro.lecuyer.rng.RandomPermutation;
import umontreal.iro.lecuyer.rng.RandomStream;
import vroom.common.utilities.dataModel.IObjectWithID;
import vroom.common.utilities.math.QuickSelect;
/**
* Creation date: Apr 5, 2010 - 5:58:47 PM<br/>
* <code>Utilities</code> is a utility class containing miscellaneous static methods
*
* @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a
* href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a
* href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a>
* @version 1.0
*/
public abstract class Utilities {
/**
* The class <code>Time</code> is a collection of utility method to deal with time
* <p>
* Creation date: Mar 27, 2012 - 4:51:30 PM.
*
* @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a
* href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a
* href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a>
* @version 1.0
*/
public abstract static class Time {
/**
* Returns the current date time in form of a string <code>yymmdd_hh-mm</code>.
*
* @return the current date time in form of a string <code>yymmdd_hh-mm</code>
*/
public static String getDateString() {
return String.format("%1$ty%1$tm%1$td_%1$tH-%1$tM",
new Date(System.currentTimeMillis()));
}
/**
* Converts a duration in s in a human friendly string.
*
* @param time
* the duration to be converted
* @param maxDigits
* the number of digits to show
* @param showMS
* <code>true</code> if ms should be displayed, <code>false</code> otherwise
* @param showAll
* <code>false</code> to show only non-null values
* @return a string of format <code>"d h m s ms"</code>, or <code>"na"</code> if <code>time</code> is negative
*/
public static String secondsToString(double time, int maxDigits, boolean showMS,
boolean showAll) {
return millisecondsToString((long) (time * 1000), maxDigits, showMS, showAll);
}
/**
* Converts a duration in ms in a human friendly string.
*
* @param time
* the duration to be converted
* @param maxDigits
* the number of digits to show
* @param showMS
* <code>true</code> if ms should be displayed, <code>false</code> otherwise
* @param showAll
* <code>false</code> to show only non-null values
* @return a string of format <code>"d h m s ms"</code>, or <code>"na"</code> if <code>time</code> is negative
*/
public static String millisecondsToString(long time, int maxDigits, boolean showMS,
boolean showAll) {
if (time < 0) {
return "na";
}
int[] duration = Time.decomposeMillis(time);
String[] labels = { "d", "h", "m", "s", "ms" };
boolean force = showAll;
StringBuilder sb = new StringBuilder(20);
int digits = 0;
for (int i = 0; i < duration.length; i++) {
if (force || (i < duration.length - 1 || showMS || digits == 0)
&& digits < maxDigits && duration[i] > 0) {
if (i != 0) {
if (i == 4 && duration[i] < 10)
sb.append(" ");
else if (duration[i] < 10
|| (i == 4 && duration[i] < 100 && duration[i] >= 10))
sb.append(" ");
}
sb.append(duration[i]);
sb.append(labels[i]);
digits++;
}
}
if (sb.length() == 0)
return "0ms";
else
return sb.toString();
}
/** The Constant sVMStartDateString. */
private static final String sVMStartDateString = getDateString();
/**
* Returns the date time at the start of the jVM in form of a string <code>yymmdd_hh-mm</code>.
*
* @return the date time at the start of the jVM in form of a string <code>yymmdd_hh-mm</code>
*/
public static String getVMStartDateString() {
return sVMStartDateString;
}
/** The Constant TIME_STAMP_FORMAT. */
public static final SimpleDateFormat TIME_STAMP_FORMAT = new SimpleDateFormat("HH:mm:ss");
/**
* Convert a duration in ns in an array containing the corresponding number of days, hours, minutes, seconds,
* milliseconds, and nanoseconds.
*
* @param time
* the duration to be converted
* @return <code>[days,hours,minutes,seconds,milliseconds]</code>
*/
public static int[] decomposeNanos(long time) {
int[] duration = new int[6];
if (time < 0) {
return duration;
}
// Days
duration[0] = (int) (time / Stopwatch.NS_IN_DAY);
time -= duration[0] * Stopwatch.NS_IN_DAY;
// Hours
duration[1] = (int) (time / Stopwatch.NS_IN_HOUR);
time -= duration[1] * Stopwatch.NS_IN_HOUR;
// Minutes
duration[2] = (int) (time / Stopwatch.NS_IN_MIN);
time -= duration[2] * Stopwatch.NS_IN_MIN;
// Seconds
duration[3] = (int) (time / Stopwatch.NS_IN_S);
time -= duration[3] * Stopwatch.NS_IN_S;
// Milliseconds
duration[4] = (int) (time / Stopwatch.NS_IN_MS);
time -= duration[4] * Stopwatch.NS_IN_S;
// Nanoseconds
duration[5] = (int) time;
return duration;
}
/**
* Convert a duration in milliseconds in an array containing the corresponding number of days, hours, minutes,
* seconds and milliseconds.
*
* @param time
* the duration to be converted
* @return <code>[days,hours,minutes,seconds,milliseconds]</code>
*/
public static int[] decomposeMillis(long time) {
int[] duration = new int[5];
if (time < 0) {
return duration;
}
// Days
duration[0] = (int) time / Stopwatch.MS_IN_DAY;
time -= duration[0] * Stopwatch.MS_IN_DAY;
// Hours
duration[1] = (int) time / Stopwatch.MS_IN_HOUR;
time -= duration[1] * Stopwatch.MS_IN_HOUR;
// Minutes
duration[2] = (int) time / Stopwatch.MS_IN_MIN;
time -= duration[2] * Stopwatch.MS_IN_MIN;
// Seconds
duration[3] = (int) time / 1000;
time -= duration[3] * 1000;
// Milliseconds
duration[4] = (int) time;
return duration;
}
}
/**
* <code>Random</code> is a collection of utility methods to deal with randomization
* <p>
* Creation date: Nov 8, 2011 - 11:41:26 AM.
*
* @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a
* href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a
* href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp" >SLP</a>
* @version 1.0
*/
public abstract static class Random {
/**
* Draw a {@code sampleSize} indexes in the set <code>{0,...,setSize-1}</code>
*
* @param setSize
* the original set size
* @param sampleSize
* the number of indexes to draw
* @param stream
* the random stream to be used
* @return an array containing {@code sampleSize} indexes in the set <code>{0,...,setSize-1}</code>
*/
public static int[] randomIndexes(int setSize, int sampleSize, RandomStream stream) {
if (sampleSize < 1)
return new int[0];
int[] indexes = new int[setSize];
for (int i = 0; i < indexes.length; i++) {
indexes[i] = i;
}
if (sampleSize >= setSize)
return indexes;
RandomPermutation.shuffle(indexes, stream);
indexes = Arrays.copyOf(indexes, sampleSize);
Arrays.sort(indexes);
return indexes;
}
/**
* Draw a sample from a collection.
*
* @param <E>
* the element type
* @param <C>
* the generic type
* @param collection
* the collection
* @param sampleSize
* the sample size
* @param stream
* the stream
* @return a sample of size {@code sampleSize} drawn from {@code collection}
*/
public static <E, C extends Collection<E>> ArrayList<E> sample(C collection,
int sampleSize, RandomStream stream) {
if (collection == null || stream == null)
throw new NullPointerException();
int[] indexes = randomIndexes(collection.size(), sampleSize, stream);
if (sampleSize >= collection.size())
return new ArrayList<E>(collection);
ArrayList<E> sample = new ArrayList<E>();
if (!AbstractSequentialList.class.isAssignableFrom(collection.getClass())
&& AbstractList.class.isAssignableFrom(collection.getClass())) {
// Faster implementation for random access lists
AbstractList<E> list = (AbstractList<E>) collection;
for (int i : indexes)
sample.add(list.get(i));
} else {
Iterator<E> it = collection.iterator();
int i = 0, itIndex = 0;
while (it.hasNext() && i < indexes.length) {
E e = it.next();
if (itIndex == indexes[i]) {
sample.add(e);
i++;
}
itIndex++;
}
}
return sample;
}
}
/**
* The class <code>SignificantPrecision</code> provides comparison methods to take into account precision issues
* using the notion of significant numbers
* <p>
* Creation date: 20/04/2013 - 12:38:09 PM
*
* @author vpillac, <a href="http://www.nicta.com.au">National ICT Australia</a>
* @version 1.0
*/
public static final class SignificantPrecision {
/** the number of significant digits to consider **/
private static int sSignificantDigits;
/**
* Getter for the number of significant digits to consider
*
* @return the number of significant digits
*/
public static int getSignificantDigits() {
return sSignificantDigits;
}
/**
* Setter for the number of significant digits to consider
*
* @param digits
* the number of significant digits
*/
public static void setSignificantDigits(int digits) {
if (digits < 0)
throw new IllegalArgumentException("The number of digits must be positive");
sSignificantDigits = digits;
}
/**
* Round a decimal value according to the {@linkplain #getSignificantDigits() number of significant digits}
* using {@link RoundingMode#HALF_EVEN}.
*
* @param d
* the decimal to be rounded
* @return {@code d} rounded with the correct number of digits
* @author vpillac
* @see Math#round(double, double, RoundingMode)
*/
public static double round(double d) {
return Math.roundSignificant(d, getSignificantDigits());
}
/**
* Returns {@code true} iif {@code round(val1)} is equal to {@code round(val2)}
*
* @param val1
* the val1
* @param val2
* the val2
* @return {@code true} if <code>round(val1)==round(val2)</code>
* @see #getZeroTolerance()
*/
public static boolean equals(double val1, double val2) {
return round(val1) == round(val2) || (Double.isNaN(val1) && Double.isNaN(val2));
}
/**
* Returns true if {@code round(val1)} is lower or equal to {@code round(val2)}
*
* @param val1
* the val1
* @param val2
* the val2
* @return {@code true} if <code>round(val1) ≤ round(val2)</code>
* @see #getZeroTolerance()
*/
public static boolean isLowerEqual(double val1, double val2) {
return round(val1) <= round(val2);
}
/**
* Returns true if {@code round(val1)} is greater or equal to {@code round(val2)}
*
* @param val1
* the val1
* @param val2
* the val2
* @return {@code true} if <code>round(val1) ≥ round(val2)</code>
* @see #getZeroTolerance()
*/
public static boolean isGreaterEqual(double val1, double val2) {
return round(val1) >= round(val2);
}
/**
* Returns true if {@code round(val1)} is strictly greater than {@code round(val2)}
*
* @param val1
* the val1
* @param val2
* the val2
* @return {@code true} if <code>round(val1) > round(val2)</code>
* @see #getZeroTolerance()
*/
public static boolean isStrictlyGreaterThan(double val1, double val2) {
return round(val1) > round(val2);
}
/**
* Returns true if {@code round(val1)} is strictly lower than {@code round(val2)}
*
* @param val1
* the val1
* @param val2
* the val2
* @return {@code true} if <code>round(val1) < round(val2)</code>
* @see #getZeroTolerance()
*/
public static boolean isStrictlyLowerThan(double val1, double val2) {
return round(val1) < round(val2);
}
/**
* Returns {@code true} if {@code round(val)} is strictly positive
*
* @param val
* the value to be tested
* @return {@code true} if {@code round(val)} is strictly positive
*/
public static boolean isStrictlyPositive(double val) {
return round(val) > 0;
}
/**
* Returns {@code true} if {@code round(val)} is greater or equal to zero
*
* @param val
* the value to be tested
* @return {@code true} if {@code round(val)} is positive
*/
public static boolean isPositive(double val) {
return round(val) >= 0;
}
/**
* Returns {@code true} if {@code round(val)} is equal to zero
*
* @param val
* the value to be tested
* @return {@code true} if {@code round(val)} is equal to zero
*/
public static boolean isZero(double val) {
return round(val) == 0;
}
}
/**
* The class <code>AbsolutePrecision</code> provides comparison methods to take into account precision issues using
* an absolute precision measure
* <p>
* Creation date: 06/03/2013 - 5:53:25 PM
*
* @author vpillac, <a href="http://www.nicta.com.au">National ICT Australia</a>
* @version 1.0
*/
public static final class AbsolutePrecision {
/** A tolerance for zero values: values that are in absolute lower than this value are considered as zero. */
private static double sZeroTolerance = 1E-9;
/**
* Getter for <code>zeroTolerance</code>, default value is {@code 1E-9}.
*
* @return the zeroTolerance
*/
public static double getZeroTolerance() {
return sZeroTolerance;
}
/**
* Setter for <code>zeroTolerance</code>, default value is {@code 1E-9}.
*
* @param zeroTolerance
* the zeroTolerance to set
*/
public static void setZeroTolerance(double zeroTolerance) {
sZeroTolerance = zeroTolerance;
}
/**
* Returns true if {@code val1} is equal to {@code val2} allowing the specified {@linkplain #getZeroTolerance().
*
* @param val1 the val1
* @param val2 the val2
* @return {@code true} if <code>|val2-val1| ≤ ε</code>
* @see #getZeroTolerance()
*/
public static boolean equals(double val1, double val2) {
return Double.doubleToLongBits(val1) == Double.doubleToLongBits(val2)
|| java.lang.Math.abs(val2 - val1) <= getZeroTolerance()
|| (Double.isNaN(val1) && Double.isNaN(val2));
}
/**
* Returns true if {@code val1} is lower or equal to {@code val2} allowing the specified
* {@linkplain #getZeroTolerance() zero tolerance}.
*
* @param val1
* the val1
* @param val2
* the val2
* @return {@code true} if <code>val1 ≤ val2 + ε</code>
* @see #getZeroTolerance()
*/
public static boolean isLowerEqual(double val1, double val2) {
return val1 <= val2 + getZeroTolerance();
}
/**
* Returns true if {@code val1} is greater or equal to {@code val2} allowing the specified
* {@linkplain #getZeroTolerance() zero tolerance}.
*
* @param val1
* the val1
* @param val2
* the val2
* @return {@code true} if <code>val1 ≥ val2 - ε</code>
* @see #getZeroTolerance()
*/
public static boolean isGreaterEqual(double val1, double val2) {
return val1 >= val2 - getZeroTolerance();
}
/**
* Returns true if {@code val1} is strictly greater than {@code val2} considering the specified
* {@linkplain #getZeroTolerance() zero tolerance}.
*
* @param val1
* the val1
* @param val2
* the val2
* @return {@code true} if <code>val1 > val2 + ε</code>
* @see #getZeroTolerance()
*/
public static boolean isStrictlyGreaterThan(double val1, double val2) {
return val1 > val2 + getZeroTolerance();
}
/**
* Returns true if {@code val1} is strictly lower than {@code val2} considering the specified
* {@linkplain #getZeroTolerance() zero tolerance}.
*
* @param val1
* the val1
* @param val2
* the val2
* @return {@code true} if <code>val1 < val2 - ε</code>
* @see #getZeroTolerance()
*/
public static boolean isStrictlyLowerThan(double val1, double val2) {
return val1 < val2 - getZeroTolerance();
}
/**
* Returns {@code true} if {@code val} is strictly greater than the specified {@linkplain #getZeroTolerance()
* zero tolerance}.
*
* @param val
* the value to be tested
* @return {@code true} if {@code val} is strictly positive
*/
public static boolean isStrictlyPositive(double val) {
return val > getZeroTolerance();
}
/**
* Returns {@code true} if {@code val} is greater than minus the specified {@linkplain #getZeroTolerance() zero
* tolerance}.
*
* @param val
* the value to be tested
* @return {@code true} if {@code val} is positive
*/
public static boolean isPositive(double val) {
return val >= -getZeroTolerance();
}
/**
* Returns {@code true} if {@code |val|} is equal to minus the specified {@linkplain #getZeroTolerance() zero
* tolerance}.
*
* @param val
* the value to be tested
* @return {@code true} if {@code val} is equal to zero
*/
public static boolean isZero(double val) {
return java.lang.Math.abs(val) <= getZeroTolerance();
}
/**
* Round a decimal value according to the {@linkplain #getZeroTolerance() zero tolerance} using
* {@link RoundingMode#HALF_EVEN}.
*
* @param d
* the decimal to be rounded
* @return {@code d} rounded according to the {@linkplain #getZeroTolerance() zero tolerance}
* @author vpillac
* @see Math#round(double, double, RoundingMode)
*/
public static double round(double d) {
return Math.round(d, getZeroTolerance(), RoundingMode.HALF_EVEN);
}
}
/**
* <code>Math</code> is a collection of utility methods
* <p>
* Creation date: May 18, 2011 - 2:47:11 PM.
*
* @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a
* href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a
* href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp" >SLP</a>
* @version 1.0
*/
public final static class Math {
/**
* <code>DeviationMeasure</code> is an enumeration of the different types of deviation measures that can be used
* to measure the difference between values and their mean
* <p>
* Creation date: May 18, 2011 - 2:58:09 PM.
*
* @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a
* href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de
* Nantes</a>-<a href ="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp"> SLP</a>
* @version 1.0
*/
public static enum DeviationMeasure {
/** Maximum absolute deviation. */
MaxAbsDev,
/** Average absolute deviation. */
AvgAbsDev,
/** Median absolute deviation. */
MedAbsDev,
/** Variance. */
Var,
/** Standard deviation. */
StdDev,
/** Maximum value, a proxy for the deviation. */
Max,
/** Minimum value, a proxy for the deviation. */
Min,
/** Difference between max value and min value. */
MaxMinGap
}
/**
* Returns the maximum value of an array.
*
* @param values
* an array of value
* @return the maximum of all elements of <code>values</code>
*/
public static int maxInt(int... values) {
if (values.length == 0)
throw new IllegalArgumentException("Must have at least one value");
int max = Integer.MIN_VALUE;
for (int i : values) {
if (i > max)
max = i;
}
return max;
}
/**
* Returns the maximum value of an array.
*
* @param values
* an array of value
* @return the maximum of all elements of <code>values</code>
*/
public static long maxLong(long... values) {
if (values.length == 0)
throw new IllegalArgumentException("Must have at least one value");
long max = Long.MIN_VALUE;
for (long i : values) {
if (i > max)
max = i;
}
return max;
}
/**
* Returns the maximum value of an array.
*
* @param values
* an array of value
* @return the maximum of all elements of <code>values</code>
*/
public static double maxDouble(double... values) {
if (values.length == 0)
throw new IllegalArgumentException("Must have at least one value");
double max = Double.NEGATIVE_INFINITY;
for (double i : values) {
if (i > max)
max = i;
}
return max;
}
/**
* Returns the index and minimum value of an array.
*
* @param values
* an array of values
* @return an array [argmin, min value]
*/
public static double[] argMin(double... values) {
if (values.length == 0)
throw new IllegalArgumentException("Must have at least one value");
double min = Integer.MAX_VALUE;
int argMin = 0;
for (int i = 0; i < values.length; i++) {
if (values[i] < min) {
min = values[i];
argMin = i;
}
}
return new double[] { argMin, min };
}
/**
* Returns the maximum value of an array.
*
* @param <T>
* the generic type
* @param values
* an array of value
* @return the maximum of all elements of <code>values</code>
*/
public static <T extends Comparable<? super T>> T max(T[] values) {
if (values.length == 0)
throw new IllegalArgumentException("Must have at least one value");
T max = null;
for (T i : values) {
if (i != null && (max == null || i.compareTo(max) > 0))
max = i;
}
return max;
}
/**
* Returns the maximum value of a collection.
*
* @param <T>
* the generic type
* @param values
* an array of value
* @return the maximum of all elements of <code>values</code>
*/
public static <T extends Comparable<? super T>> T max(Collection<T> values) {
if (values.isEmpty())
throw new IllegalArgumentException("Must have at least one value");
T max = null;
for (T i : values) {
if (i != null && (max == null || i.compareTo(max) > 0))
max = i;
}
return max;
}
/**
* Returns the <code>k</code> biggest values of an array.
*
* @param <T>
* the generic type
* @param values
* an array of value
* @param k
* the number of elements to extract
* @return the <code>n</code> biggest elements of <code>values</code> sorted in ascending order
* @see QuickSelect#max(Comparable[], int, boolean, boolean)
*/
public static <T extends Comparable<? super T>> T[] max(T[] values, int k) {
if (values.length == 0 || k == 0)
return Arrays.copyOf(values, 0);
if (k == 1) {
// More efficient implementation
T[] r = Arrays.copyOf(values, 1);
r[0] = max(values);
return r[0] != null ? r : Arrays.copyOf(values, 0);
}
if (k >= values.length) {
int nonNull = 0;
for (T v : values)
if (v != null)
nonNull++;
T[] r = Arrays.copyOf(values, nonNull);
int i = 0;
for (T v : values)
if (v != null)
r[i++] = v;
Arrays.sort(r);
return r;
}
return QuickSelect.max(values, k, true, true);
}
/**
* Returns the <code>k</code> biggest values of an array.
*
* @param values
* an array of double
* @param k
* the number of elements to extract
* @return the <code>n</code> biggest elements of <code>values</code> sorted in ascending order
* @see QuickSelect#max(Comparable[], int, boolean, boolean)
*/
public static double[] max(double[] values, int k) {
if (values.length == 0)
return new double[0];
if (k == 1) {
// More efficient implementation
double[] r = Arrays.copyOf(values, 1);
r[0] = maxDouble(values);
return r[0] != Double.NEGATIVE_INFINITY ? r : new double[0];
}
if (k >= values.length) {
double[] r = Arrays.copyOf(values, values.length);
Arrays.sort(r);
return r;
}
Double[] clone = new Double[values.length];
for (int i = 0; i < clone.length; i++) {
clone[i] = values[i];
}
Double[] rD = QuickSelect.max(clone, k, false, true);
double[] r = new double[rD.length];
for (int i = 0; i < r.length; i++) {
r[i] = rD[i];
}
return r;
}
/**
* Returns the minimum value of an array.
*
* @param values
* an array of values
* @return the minimum of all elements of <code>values</code>
*/
public static int minInt(int... values) {
if (values.length == 0)
throw new IllegalArgumentException("Must have at least one value");
int min = Integer.MAX_VALUE;
for (int i : values) {
if (i < min)
min = i;
}
return min;
}
/**
* Returns the index and minimum value of an array.
*
* @param values
* an array of values
* @return an array [argmin, min value]
*/
public static int[] argMin(int... values) {
if (values.length == 0)
throw new IllegalArgumentException("Must have at least one value");
int min = Integer.MAX_VALUE;
int argMin = 0;
for (int i = 0; i < values.length; i++) {
if (values[i] < min) {
min = values[i];
argMin = i;
}
}
return new int[] { argMin, min };
}
/**
* Returns the maximum value of an array.
*
* @param values
* an array of value
* @return the maximum of all elements of <code>values</code>
*/
public static long minLong(long... values) {
if (values.length == 0)
throw new IllegalArgumentException("Must have at least one value");
long min = Long.MAX_VALUE;
for (long i : values) {
if (i < min)
min = i;
}
return min;
}
/**
* Returns the maximum value of an array.
*
* @param values
* an array of value
* @return the maximum of all elements of <code>values</code>
*/
public static double minDouble(double... values) {
if (values.length == 0)
throw new IllegalArgumentException("Must have at least one value");
double min = Double.POSITIVE_INFINITY;
for (double i : values) {
if (i < min)
min = i;
}
return min;
}
/**
* Returns the minimum value of an array.
*
* @param <T>
* the generic type
* @param values
* an array of value
* @return the maximum of all elements of <code>values</code>
*/
public static <T extends Comparable<? super T>> T min(T[] values) {
if (values.length == 0)
throw new IllegalArgumentException("Must have at least one value");
T min = null;
for (T i : values) {
if (i != null && (min == null || i.compareTo(min) < 0))
min = i;
}
return min;
}
/**
* Returns the minimum value of a collection.
*
* @param <T>
* the generic type
* @param values
* an array of value
* @return the maximum of all elements of <code>values</code>
*/
public static <T extends Comparable<? super T>> T min(Collection<T> values) {
if (values.isEmpty())
throw new IllegalArgumentException("Must have at least one value");
T min = null;
for (T i : values) {
if (i != null && (min == null || i.compareTo(min) < 0))
min = i;
}
return min;
}
/**
* Returns the <code>n</code> smallest values of an array.
*
* @param <T>
* the generic type
* @param values
* an array of value
* @param k
* the number of elements to extract
* @return the <code>n</code> smallest elements of <code>values</code> sorted in ascending order
* @see QuickSelect#max(Comparable[], int, boolean, boolean)
*/
public static <T extends Comparable<? super T>> T[] min(T[] values, int k) {
if (values.length == 0 || k == 0)
return Arrays.copyOf(values, 0);
if (k == 1) {
// More efficient implementation
T[] r = Arrays.copyOf(values, 1);
r[0] = min(values);
return r[0] != null ? r : Arrays.copyOf(values, 0);
}
return QuickSelect.min(values, k, true, true);
}
/**
* Returns the <code>k</code> smallest values of an array.
*
* @param values
* an array of double
* @param k
* the number of elements to extract
* @return the <code>n</code> biggest elements of <code>values</code> sorted in ascending order
* @see QuickSelect#max(Comparable[], int, boolean, boolean)
*/
public static double[] min(double[] values, int k) {
if (values.length == 0)
return new double[0];
if (k == 1) {
// More efficient implementation
double[] r = Arrays.copyOf(values, 1);
r[0] = minDouble(values);
return r[0] != Double.POSITIVE_INFINITY ? r : new double[0];
}
Double[] clone = new Double[values.length];
for (int i = 0; i < clone.length; i++) {
clone[i] = values[i];
}
Double[] rD = QuickSelect.min(clone, k, false, true);
double[] r = new double[rD.length];
for (int i = 0; i < r.length; i++) {
r[i] = rD[i];
}
return r;
}
/**
* Returns the sum of an array of values.
*
* @param values
* an array of values to be averaged
* @return the sum of an array of values
*/
public static double sum(double... values) {
double sum = 0;
for (double d : values) {
sum += d;
}
return sum;
}
/**
* Sum the second dimension of a matrix
*
* @param values
* a matrix
* @return an array {@code sum} containing the sum of the <em>rows</em>:
* <code>sum[i]=values[i][0]+...+values[i][values[i].length-1]</code>
* @author vpillac
*/
public static double[] sum(double[][] values) {
double[] sum = new double[values.length];
for (int i = 0; i < values.length; i++) {
sum[i] = Utilities.Math.sum(values[i]);
}
return sum;
}
/**
* Returns the arithmetic mean of an array of values.
*
* @param values
* the values
* @return the arithmetic mean of of {@code values}
*/
public static double mean(double... values) {
if (values.length == 0)
return 0;
double avg = sum(values);
return avg / values.length;
}
/**
* Returns the arithmetic mean of a collection of values.
*
* @param values
* the values
* @return the arithmetic mean of of {@code values}
*/
public static double mean(Collection<Double> values) {
if (values.isEmpty())
return 0;
double sum = 0;
for (Double d : values)
sum += d;
return sum / values.size();
}
/**
* Returns the median of a collection of values.
*
* @param values
* the values
* @return the median of {@code values}
*/
public static double median(Collection<Double> values) {
return percentile(values, 50);
}
/**
* Return the {@code k}-th percentile of a collection values.
*
* @param values
* the values
* @param k
* the desired percentile
* @return the {@code k}-th percentile of {@code values}
*/
public static double percentile(Collection<Double> values, int k) {
if (values.isEmpty())
throw new IllegalArgumentException("Collection of values is empty");
if (k < 0 || k > 100)
throw new IllegalArgumentException("Illegal value for k: " + k);
Double[] val = values.toArray(new Double[values.size()]);
Arrays.sort(val);
return val[(int) (val.length / 100d * k)];
}
/**
* Return the frequency histogram data for a serie of values
*
* @param values
* @param buckectCount
* @return a 2-dimension {@code hist} array containing for each bucket {@code i} the bucket upper bound
* {@code hist[i][0]} and the nummber of values in that bucket {@code hist[i][1]}
* @author vpillac
*/
public static double[][] freqHistogram(double[] values, int buckectCount) {
double min = java.lang.Math.floor(minDouble(values)) - 1;
double max = java.lang.Math.ceil(maxDouble(values)) + 1;
double bucketWidth = (max - min) / buckectCount;
double[][] hist = new double[2][buckectCount];
for (int i = 0; i < buckectCount; i++) {
hist[0][i] = min + (i + 1) * bucketWidth;
hist[1][i] = 0;
}
for (double value : values) {
boolean counted = false;
double lb = min;
double ub = hist[0][0];
for (int i = 0; i < buckectCount & !counted; i++) {
if (lb <= value && value < ub) {
hist[1][i]++;
}
lb = ub;
ub = ub += bucketWidth;
}
}
return hist;
}
/**
* Returns the sum of an array of values.
*
* @param values
* an array of values to be averaged
* @return the sum of an array of values
*/
public static int sum(int... values) {
int sum = 0;
for (int d : values) {
sum += d;
}
return sum;
}
/**
* Returns the average of an array of values.
*
* @param values
* an array of values to be averaged
* @return the average of an array of values
*/
public static double average(int... values) {
double avg = sum(values);
return avg / values.length;
}
/**
* Evaluate the deviation of the <code>values</code> with respect to the given deviation metric.
*
* @param devMetric
* the deviation metric to be used
* @param values
* the values which variance/deviation will be evaluated
* @return the deviation of <code>values</code> with respect to <code>devMetric</code>
*/
public static double deviation(DeviationMeasure devMetric, Collection<Double> values) {
if (values.size() == 0)
return 0;
if (devMetric == DeviationMeasure.Min || devMetric == DeviationMeasure.Max) {
return devMetric == DeviationMeasure.Min ? Utilities.Math.min(values)
: Utilities.Math.max(values);
}
double avg = Utilities.Math.mean(values);
double eval = Double.NaN;
switch (devMetric) {
case MaxAbsDev:
eval = 0;
for (double v : values) {
eval = java.lang.Math.max(eval, java.lang.Math.abs(avg - v));
}
break;
case AvgAbsDev:
eval = 0;
for (double v : values) {
eval += java.lang.Math.abs(avg - v);
}
eval /= values.size();
break;
case StdDev:
eval = 0;
for (double v : values) {
eval += java.lang.Math.pow(java.lang.Math.abs(avg - v), 2);
}
eval = java.lang.Math.sqrt(eval);
break;
case MaxMinGap:
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
for (double v : values) {
if (v < min)
min = v;
if (v > max)
max = v;
}
return max - min;
default:
throw new UnsupportedOperationException(devMetric + " is not supported yet");
}
return eval;
}
/**
* Evaluate the deviation of the <code>values</code> with respect to the given deviation metric.
*
* @param devMetric
* the deviation metric to be used
* @param values
* the values which variance/deviation will be evaluated
* @return the deviation of <code>values</code> with respect to <code>devMetric</code>
*/
public static double deviation(DeviationMeasure devMetric, double... values) {
if (values.length == 0)
return 0;
if (devMetric == DeviationMeasure.Min || devMetric == DeviationMeasure.Max) {
return devMetric == DeviationMeasure.Min ? Utilities.Math.minDouble(values)
: Utilities.Math.maxDouble(values);
}
double avg = Utilities.Math.mean(values);
double eval = Double.NaN;
switch (devMetric) {
case MaxAbsDev:
eval = 0;
for (double v : values) {
eval = java.lang.Math.max(eval, java.lang.Math.abs(avg - v));
}
break;
case AvgAbsDev:
eval = 0;
for (double v : values) {
eval += java.lang.Math.abs(avg - v);
}
eval /= values.length;
break;
case StdDev:
eval = 0;
for (double v : values) {
eval += java.lang.Math.pow(java.lang.Math.abs(avg - v), 2);
}
eval /= values.length;
eval = java.lang.Math.sqrt(eval);
break;
case Var:
eval = 0;
for (double v : values) {
eval += java.lang.Math.pow(java.lang.Math.abs(avg - v), 2);
}
eval /= values.length;
break;
case MaxMinGap:
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
for (double v : values) {
if (v < min)
min = v;
if (v > max)
max = v;
}
eval = max - min;
break;
default:
throw new UnsupportedOperationException(devMetric + " is not supported yet");
}
return eval;
}
/**
* Round a decimal with the given number of significant digits using {@linkplain RoundingMethod rounding method}
* .
*
* @param decimal
* the decimal to be rounded
* @param digits
* the number of significant digits
* @param mode
* the rounding mode
* @return {@code decimal} rounded to the given number of significant digits
*/
public static double roundSignificant(double decimal, int digits) {
BigDecimal bd = new BigDecimal(decimal);
bd = bd.round(new MathContext(digits));
return bd.doubleValue();
}
/**
* Round a decimal with the given precision using the specified {@linkplain RoundingMethod rounding method}.
*
* @param decimal
* the decimal to be rounded
* @param precision
* the precision (number of digits)
* @param mode
* the rounding mode
* @return {@code decimal} rounded to the given {@code precision} according to {@code method}
*/
public static double round(double decimal, int precision, RoundingMode mode) {
if (mode == RoundingMode.UNNECESSARY)
return decimal;
BigDecimal bd = new BigDecimal(decimal).setScale(precision, mode);
return bd.doubleValue();
}
/**
* Round a decimal with the given precision using the specified {@linkplain RoundingMethod rounding method}.
*
* @param decimal
* the decimal to be rounded
* @param precision
* the precision (for instance 1E-6)
* @param mode
* the rounding mode
* @return {@code decimal} rounded to the given {@code precision} according to {@code method}
*/
public static double round(double decimal, double precision, RoundingMode mode) {
return round(decimal, -(int) java.lang.Math.log10(precision), mode);
}
/**
* Returns {@code true} if {@code small} is included in {@code big}.
*
* @param big
* the big
* @param small
* the small
* @return {@code true} if {@code small} is included in {@code big}
*/
public static boolean isIncluded(Set<?> big, Set<?> small) {
if (small.size() > big.size())
return false;
for (Object e : small)
if (!big.contains(e))
return false;
return true;
}
/**
* Returns {@code true} if {@code set1} is equal to {@code set2}, i.e. if they contain the same elements
*
* @param set1
* the set1
* @param set2
* the set2
* @return {@code true} if {@code set1} is equal to {@code set2}
*/
public static boolean equals(Set<?> set1, Set<?> set2) {
return set1.size() == set2.size() && isIncluded(set1, set2);
}
}
/**
* Creates a iterator of the desired type based on the given iterator
* <p/>
* <b>Warning</b> This operation is not type safe.
*
* @param <S>
* the generic type
* @param <D>
* the generic type
* @param iterator
* the iterator
* @return an iterator of type <code>Iterator<</>D></code> based on the given iterator
*/
public static <S, D> Iterator<D> castIterator(final Iterator<S> iterator) {
return new Iterator<D>() {
private final Iterator<S> it = iterator;
@Override
public boolean hasNext() {
return it.hasNext();
}
@SuppressWarnings("unchecked")
@Override
public D next() {
return (D) it.next();
}
@Override
public void remove() {
it.remove();
}
};
}
/**
* Creates a iterator of the desired type based on the given iterator
* <p/>
* <b>Warning</b> This operation is not type safe.
*
* @param <S>
* the generic type
* @param <D>
* the generic type
* @param iterator
* the iterator
* @return an iterator of type <code>Iterator<</>D></code> based on the given iterator
*/
public static <S, D> ListIterator<D> castIterator(final ListIterator<S> iterator) {
return new ListIterator<D>() {
private final ListIterator<S> it = iterator;
@SuppressWarnings("unchecked")
@Override
public void add(D e) {
it.add((S) e);
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public boolean hasPrevious() {
return it.hasPrevious();
}
@SuppressWarnings("unchecked")
@Override
public D next() {
return (D) it.next();
}
@Override
public int nextIndex() {
return it.nextIndex();
}
@SuppressWarnings("unchecked")
@Override
public D previous() {
return (D) it.previous();
}
@Override
public int previousIndex() {
return it.previousIndex();
}
@Override
public void remove() {
it.remove();
}
@SuppressWarnings("unchecked")
@Override
public void set(D e) {
it.set((S) e);
}
};
}
/**
* Collection pseudo-casting.
* <p/>
* Will copy all elements of the given collection to a list of the given generic type
* <p/>
* Supports {@link LinkedList} and {@link ArrayList}, all other implementations will be casted in a
*
* @param <S>
* the source type
* @param <D>
* the destination type
* @param source
* the collection to be casted
* @return a List with generic type <code><D></code> containing the casted elements of the <code>source</code> list
* {@link ArrayList}.
* <p/>
* <b>Warning</b> This operation is not type safe.
*/
@SuppressWarnings("unchecked")
public static <S, D> List<D> convertToList(Collection<S> source) {
if (source == null) {
return null;
}
List<D> casted = null;
if (source instanceof LinkedList<?>) {
casted = new LinkedList<D>();
} else {
casted = new ArrayList<D>();
}
for (S s : source) {
casted.add((D) s);
}
return casted;
}
/**
* Collection pseudo-casting.
* <p/>
* Will copy all elements of the given collection to a {@link HashSet} of the given generic type
* <p/>
* <b>Warning</b> This operation is not type safe.
*
* @param <S>
* the source type
* @param <D>
* the destination type
* @param source
* the collection to be casted
* @return a {@link HashSet} with generic type <code><D></code> containing the casted elements of the
* <code>source</code> list
*/
@SuppressWarnings("unchecked")
public static <S, D> Set<D> convertToSet(Collection<S> source) {
if (source == null) {
return null;
}
Set<D> casted = null;
casted = new HashSet<D>();
for (S s : source) {
casted.add((D) s);
}
return casted;
}
/**
* Copy an <code>int</code> array into a <code>double</code> array.
*
* @param array
* the array
* @return a copy of <code>array</code> in a array of <code>double</code>
*/
public static double[] copyToDoubleArray(int[] array) {
double[] copy = new double[array.length];
for (int s = 0; s < array.length; s++) {
copy[s] = array[s];
}
return copy;
}
/**
* Copy a <code>double</code> array into a <code>int</code> array.
*
* @param array
* the array
* @return a copy of <code>array</code> in a array of <code>int</code>
*/
public static int[] copyToIntArray(double[] array) {
int[] copy = new int[array.length];
for (int s = 0; s < array.length; s++) {
copy[s] = (int) array[s];
}
return copy;
}
/**
* Equality check.
*
* @param a
* the a
* @param b
* the b
* @return <code>a==b || (a!=null && a.equals(b))</code>
*/
public static boolean equal(Object a, Object b) {
return a == b || (a != null && a.equals(b));
}
/**
* Recursively unwrap a wrapper to get the underlying object.
*
* @param <O>
* the generic type
* @param wrapper
* the wrapper
* @param wrappedClass
* the wrapped class
* @return the wrapped object
*/
@SuppressWarnings("unchecked")
public static <O> O getWrappedObjectRec(Wrapper<O> wrapper, Class<O> wrappedClass) {
O object = wrapper.getWrappedObject();
Object tmp = object;
while (tmp instanceof Wrapper<?>) {
tmp = ((Wrapper<?>) tmp).getWrappedObject();
if (wrappedClass.isAssignableFrom(tmp.getClass())) {
object = (O) tmp;
}
}
return object;
}
/**
* Factory method for compatible constructors.
*
* @param <O>
* the type of object to be returned
* @param clazz
* the class to be instantiated
* @param argsTypes
* the types of the arguments to be passed to the class constructor
* @param args
* the arguments to be passed to the class constructor (can include <code>null</code> elements)
* @return a new instance of the class defined as value of the parameter <code>clazz</code>
* @throws IllegalArgumentException
* if the new object could not be instantiated because of a error in the arguments
* @see Reflection#getMatchingConstructor(Class, Class...)
*/
@SuppressWarnings("unchecked")
public static <O> O newInstance(Class<O> clazz, Class<?>[] argsTypes, Object[] args)
throws IllegalArgumentException {
if (clazz == null) {
throw new IllegalArgumentException("The class argument cannot be null");
}
O object = null;
Constructor<?> cons;
try {
cons = Reflection.getMatchingConstructor(clazz, argsTypes);
if (cons != null) {
object = (O) cons.newInstance(args);
} else {
throw new IllegalArgumentException(String.format(
"No matching constructor found for class:%s : args:%s",
clazz.getSimpleName(), Arrays.toString(argsTypes)));
}
} catch (Exception e) {
throw new IllegalArgumentException(String.format(
"Exception caught when trying to instanciate class:%s : args:%s, exception:%s",
clazz.getSimpleName(), Arrays.toString(argsTypes), e), e);
}
return object;
}
/**
* Factory method for parameters which values are types. <br/>
* Will deduce the constructor by using the <code>class</code> of the given arguments <code>args</code>
*
* @param <O>
* the type of object to be returned
* @param clazz
* the class to be instantiated
* @param args
* the arguments to be passed to the class constructor (all elements should be <b>not <code>null</code>
* </b>)
* @return a new instance of the class defined as value of the parameter <code>clazz</code>
* @throws IllegalArgumentException
* if the new object could not be instantiated because of a error in the arguments
* @see #newInstance(Class, Class[], Object[])
*/
public static <O> O newInstance(Class<O> clazz, Object... args) throws IllegalArgumentException {
Class<?>[] argsClasses = new Class<?>[args.length];
// Deducing the argument types
for (int i = 0; i < argsClasses.length; i++) {
if (args[i] != null) {
argsClasses[i] = args[i].getClass();
} else {
argsClasses[i] = Object.class;
}
}
return newInstance(clazz, argsClasses, args);
}
/**
* Cast a string to an array of integers
* <p>
* String should have the format <code>"[1,2,3]"</code>.
*
* @param array
* the string to be cats
* @return an array containing the parsed integers
*/
public static int[] toIntArray(String array) {
// Empty array []
if (array.length() == 2)
return new int[0];
String[] cast = array.substring(1, array.length() - 1).split(",");
int[] result = new int[cast.length];
for (int i = 0; i < cast.length; i++) {
result[i] = Integer.parseInt(cast[i].replaceAll("\\s+", ""));
}
return result;
}
/**
* Cast a list to an array of integers.
*
* @param list
* the list to be cast
* @return an array containing the original list
*/
public static int[] toIntArray(List<Integer> list) {
// Empty array []
int[] result = new int[list.size()];
int i = 0;
for (int v : list) {
result[i++] = v;
}
return result;
}
/**
* Cast a string to an array of longs
* <p>
* String should have the format <code>"[1,2,3]"</code>.
*
* @param array
* the string to be cast
* @return an array containing the parsed longs
*/
public static long[] toLongArray(String array) {
// Empty array []
if (array.length() == 2)
return new long[0];
String[] cast = array.substring(1, array.length() - 1).split(",");
long[] result = new long[cast.length];
for (int i = 0; i < cast.length; i++) {
result[i] = Long.valueOf(cast[i]);
}
return result;
}
/**
* Cast a string to an array of double
* <p>
* String should have the format <code>"[1.2,2.6,3]"</code>
*
* @param array
* the string to be casted
* @return an array containing the parsed double
*/
public static double[] toDoubleArray(String array) {
// Empty array []
if (array.length() == 2)
return new double[0];
String[] cast = array.substring(1, array.length() - 1).split(",");
double[] result = new double[cast.length];
for (int i = 0; i < cast.length; i++) {
result[i] = Double.valueOf(cast[i]);
}
return result;
}
/**
* Cast a string to an array of objects
* <p>
* String should have the format <code>"[a,b,c]"</code>.
*
* @param array
* the string to be parsed
* @return the parsed array
*/
public static String[] toArray(String array) {
// Empty array []
if (array.length() == 2)
return new String[0];
return array.substring(1, array.length() - 1).split(",");
}
/**
* Converts a collection to a short string of the form <code>[a,b,c]</code> with comma separated values and no
* spaces.
*
* @param collection
* the collection
* @return the corresponding string
*/
public static String toShortString(Iterable<?> collection) {
return toShortString(collection, ',', true);
}
/**
* Converts a collection to a short string of the form <code>[a,b,c]</code>.
*
* @param collection
* the collection
* @param separator
* the character used between value
* @param brackets
* the brackets
* @return the corresponding string {@code true} to include opening/closing brackets
*/
public static String toShortString(Iterable<?> collection, char separator, boolean brackets) {
if (collection == null)
return "null";
StringBuilder s = new StringBuilder(255);
if (brackets)
s.append("[");
Iterator<?> it = collection.iterator();
while (it.hasNext()) {
s.append(toShortString(it.next()));
if (it.hasNext())
s.append(separator);
}
if (brackets)
s.append("]");
return s.toString();
}
/**
* Converts an object to a (short) string.
*
* @param object
* the object to be converted
* @return a short string describing the array
* @see Class#isArray()
*/
public static String toShortString(Object object) {
if (object == null)
return "null";
if (IToShortString.class.isAssignableFrom(object.getClass()))
return ((IToShortString) object).toShortString();
else if (object.getClass().isArray()) {
final int l = Array.getLength(object);
StringBuilder s = new StringBuilder(l * 3);
s.append("[");
for (int i = 0; i < l; i++) {
Object v = Array.get(object, i);
s.append(toShortString(v));
if (i < l - 1)
s.append(",");
}
s.append("]");
return s.toString();
} else if (Iterable.class.isAssignableFrom(object.getClass())) {
return toShortString((Iterable<?>) object);
} else {
return object.toString();
}
}
/**
* Converts an object to a {@link String}, automatically handling arrays and collections.
*
* @param o
* the object to be converted to a {@link String}
* @return a {@link String} describing the object
*/
public static String toString(Object o) {
if (o == null)
return null;
else if (o instanceof Collection<?>)
return toShortString((Collection<?>) o);
else if (o.getClass().isArray())
return toShortString(o);
else
return o.toString();
}
/**
* Converts an array to a short string of the form <code>[a,b,c]</code> with comma separated values and no spaces.
*
* @param <T>
* the generic type
* @param array
* the array
* @return the corresponding string
*/
public static <T> String toShortString(T[] array) {
return toShortString(array, ',', true);
}
/**
* Converts an array to a short string of the form <code>[a,b,c]</code>.
*
* @param <T>
* the generic type
* @param array
* the array
* @param separator
* the character used between value
* @param brackets
* the brackets
* @return the corresponding string {@code true} to include opening/closing brackets
*/
public static <T> String toShortString(T[] array, char separator, boolean brackets) {
if (array == null)
return "null";
StringBuilder s = new StringBuilder(array.length * 3);
if (brackets)
s.append("[");
for (int i = 0; i < array.length; i++) {
s.append(array[i]);
if (i < array.length - 1)
s.append(separator);
}
if (brackets)
s.append("]");
return s.toString();
}
/**
* Compare two arrays of same size element by element.
*
* @param a
* the a
* @param b
* the b
* @return <code>0 if a==b</code>, <code>1 if a>b</code>, <code>-1 if a<b</code> and {@link Integer#MAX_VALUE}
* otherwise
*/
public static int compare(int[] a, int[] b) {
if (a.length != b.length)
throw new IllegalArgumentException("Both arrays must be of same size");
boolean greater = true;
boolean lower = true;
boolean equal = true;
for (int i = 0; i < a.length; i++) {
if (a[i] < b[i]) {
greater = false;
equal = false;
} else if (a[i] > b[i]) {
lower = false;
equal = false;
}
}
return equal ? 0 : greater ? 1 : lower ? -1 : Integer.MAX_VALUE;
}
/**
* Merge two array in a single one.
*
* @param <T>
* the generic type
* @param array1
* the first array
* @param array2
* the second array
* @return an array containing all elements from {@code array1} and {@code array2} (the first element is the first
* element of {@code array1})
*/
public static <T> T[] merge(T[] array1, T[] array2) {
T[] merge = Arrays.copyOf(array1, array1.length + array2.length);
for (int i = 0; i < array2.length; i++) {
merge[i + array1.length] = array2[i];
}
return merge;
}
/**
* Search for the maximum {@link IObjectWithID#getID() id} in a collection of objects
*
* @param objects
* @return the maximium id found in {@code objects}
* @author vpillac
*/
public static int getMaxId(Collection<? extends IObjectWithID> objects) {
if (objects.isEmpty())
return 0;
int maxId = 0;
for (IObjectWithID o : objects) {
if (o.getID() > maxId)
maxId = o.getID();
}
return maxId;
}
/**
* Unified path for output file, dated to the start of the jVM.
*
* @param directory
* the destination directory
* @param runName
* the name of the run
* @param comment
* a comment for this file
* @param extension
* the extension of the file (without dots)
* @return a unified path for the desired output file
*/
public static String getUnifiedOutputFilePath(String directory, String runName, String comment,
String extension) {
File f = new File(String.format("%s/%s_%s_%s.%s", directory, Time.getVMStartDateString(),
runName, comment, extension));
int i = 1;
while (f.exists()) {
f = new File(String.format("%s/%s_%s_%s-%s.%s", directory, Time.getVMStartDateString(),
runName, comment, i++, extension));
}
return f.getPath();
}
/**
* List files.
*
* @param path
* the path
* @param filePattern
* the file pattern
* @return a list of the files contains in the directory specified by <code>path</code> that match the given pattern
* @throws FileNotFoundException
* the file not found exception
*/
public static List<File> listFiles(String path, String filePattern)
throws FileNotFoundException {
LinkedList<File> files = new LinkedList<File>();
File folder = new File(path);
if (!folder.exists())
throw new FileNotFoundException("Folder not found, path:" + path);
for (String f : folder.list()) {
if (f.matches(filePattern)) {
files.add(new File(String.format("%s%s%s", path, File.separatorChar, f)));
}
}
Collections.sort(files, new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
return o1.getName().compareTo(o2.getName());
}
});
return files;
}
/** The Number format. */
private static String sNumberFormat = "0.###";
/**
* Set the default format number to be used.
*
* @param format
* a string of the form <code>###0.000</code> defining the formating of decimal numbers
* @see #format(Number)
*/
public static void setDefaultNumberFormat(String format) {
sNumberFormat = format;
sFormat = new DecimalFormat(sNumberFormat);
}
/** The Format. */
private static DecimalFormat sFormat = new DecimalFormat(sNumberFormat);
/**
* Format a number.
*
* @param val
* the val
* @return a string describing the given number with the default precision
* @see #setDefaultNumberFormat(String)
*/
public static String format(Object val) {
if (val == null)
return "null";
else if (Number.class.isAssignableFrom(val.getClass()))
// return NumberFormat.getNumberInstance().format(val);
return sFormat.format(val);
// else if (val instanceof Double || val instanceof Float)
else
return val.toString();
}
}