/** * */ package net.varkhan.base.containers.array; import net.varkhan.base.containers.type.DoubleContainer; import java.io.IOException; import java.util.NoSuchElementException; /** * <b>Static double arrays manipulation utilities.</b> * <p/> * Utilities for manipulating arrays of doubles. * <p/> * * @author varkhan * @date Nov 15, 2010 * @time 12:07:07 AM */ public class DoubleArrays { /** * Private empty constructor that forbids instantiation of this class. */ protected DoubleArrays() { } /********************************************************************************* ** Matching operations **/ /** * Indicates whether two double arrays are equal. * * @param array1 the first array * @param array2 the second array * * @return {@code true} iff the arrays are either both {@code null} or * have the same number of elements, and the values of elements in the * same positions are equal */ public static boolean equals(double[] array1, double[] array2) { if(array1==null) return array2==null; if(array1.length!=array2.length) return false; for(int i=0;i<array1.length;i++) { if(array1[i]!=array2[i]) return false; } return true; } /** * Returns the position of the first occurrence of a value inside an array. * * @param item the value to search for * @param array the array to search * * @return {@literal -1} if {@code item} was not found in {@code array}, * the position of the first element of the array equal to {@code item} */ public static int indexOf(double item, double... array) { if(array==null) return -1; final int length = array.length; for(int i=0;i<length;i++) if(item==array[i]) return i; return -1; } /** * Returns the position of the first occurrence of an array as a subsequence * of an other array. * * @param sub the subsequence to find * @param pos the starting point in the array * @param array the array * * @return the smallest index {@code idx} greater than {@code pos} such that * the elements of {@code array} starting at {@code idx} are exactly those of * {@code sub} ({@code -1} is returned if {@code sub} is not a subsequence * of {@code array}) */ public static int indexOf(double[] sub, int pos, double[] array) { if(array==null) return sub==null ? 0 : -1; match: while(pos<array.length) { for(int i=0;i<sub.length;i++) { if(pos+i>=array.length) return -1; if(array[pos+i]!=sub[i]) { pos++; continue match; } } return pos; } return -1; } /********************************************************************************* ** Sorting and search **/ /** * Sorts an array in place, in ascending order. * * @param ary the array to sort * @return the number of swap operations required for the sorting */ public static int sortInc(double... ary) { return sortInc(ary, 0, ary.length-1); } /** * Sorts an array in place, in descending order. * * @param ary the array to sort * @return the number of swap operations required for the sorting */ public static int sortDec(double... ary) { return sortDec(ary, 0, ary.length-1); } /** * Sorts an array segment in place, in ascending order. * * @param ary the array to sort * @param inf the minimum index * @param sup the maximum index * @return the number of swap operations required for the sorting */ public static int sortInc(double[] ary, int inf, int sup) { int cnt = 0; int beg = ((inf+sup)>>1)+1; // inf + (sup-inf+1)/2 - 1 = (sup+inf)/2+1 while(beg>inf) { beg --; cnt += heapDownInc(ary,beg,sup); } int end = sup; while(end>=inf) { double v = ary[end]; ary[end] = ary[inf]; ary[inf] = v; end --; cnt += 1 + heapDownInc(ary,inf,end); } return cnt; } /** * Sorts an array segment in place, in descending order. * * @param ary the array to sort * @param inf the minimum index * @param sup the maximum index * @return the number of swap operations required for the sorting */ public static int sortDec(double[] ary, int inf, int sup) { int cnt = 0; int beg = ((inf+sup)>>1)+1; // inf + (sup-inf+1)/2 - 1 = (sup+inf)/2+1 while(beg>inf) { beg --; cnt += heapDownDec(ary,beg,sup); } int end = sup; while(end>=inf) { double v = ary[end]; ary[end] = ary[inf]; ary[inf] = v; end --; cnt += 1 + heapDownDec(ary,inf,end); } return cnt; } protected static int heapDownInc(double[] ary, int inf, int sup) { int cnt = 0; int pos = inf; int cld = (pos<<1)+1; while(cld<=sup) { int swp = pos; if(ary[swp]<ary[cld]) swp = cld; cld ++; if(cld<=sup) { if(ary[swp]<ary[cld]) swp = cld; } if(swp==pos) return cnt; double v = ary[pos]; ary[pos] = ary[swp]; ary[swp] = v; cnt ++; pos = swp; cld = (pos<<1)+1; } return cnt; } protected static int heapDownDec(double[] ary, int inf, int sup) { int cnt = 0; int pos = inf; int cld = (pos<<1)+1; while(cld<=sup) { int swp = pos; if(ary[swp]>ary[cld]) swp = cld; cld ++; if(cld<=sup) { if(ary[swp]>ary[cld]) swp = cld; } if(swp==pos) return cnt; double v = ary[pos]; ary[pos] = ary[swp]; ary[swp] = v; cnt ++; pos = swp; cld = (pos<<1)+1; } return cnt; } /** * Finds an object in a sorted array, in ascending order. * * @param ary the sorted array * @param inf the minimum index * @param sup the maximum index * @param key the value to search for * * @return the key position in the array, or {@code -(inspos+1)}, * where {@code inspos} is the index of the first value in the * array bigger than {@code key} */ public static int searchInc(double[] ary, int inf, int sup, double key) { int min=inf; int max=sup-1; while(min<=max) { int med=(min+max)>>>1; double medVal=ary[med]; if(medVal<key) min=med+1; else if(medVal>key) max=med-1; else return med; // key found } return -(min+1); // key not found. } /** * Finds an object in a sorted array, in descending order. * * @param ary the sorted array * @param inf the minimum index * @param sup the maximum index * @param key the value to search for * * @return the key position in the array, or {@code -(inspos+1)}, * where {@code inspos} is the index of the first value in the * array bigger than {@code key} */ public static int searchDec(double[] ary, int inf, int sup, double key) { int min=inf; int max=sup-1; while(min<=max) { int med=(min+max)>>>1; double medVal=ary[med]; if(medVal<key) min=med+1; else if(medVal>key) max=med-1; else return med; // key found } return -(min+1); // key not found. } /** * Computes the union of segments in two sorted arrays, in ascending order. * * @param ary1 the first sorted array * @param beg1 the start position of the first segment * @param len1 the length of the first segment * @param ary2 the second sorted array * @param beg2 the start position of the second segment * @param len2 the length of the second segment * @return the union of the two segments, with duplicates removed */ public static double[] unionInc(double[] ary1, int beg1, int len1, double[] ary2, int beg2, int len2) { int len = len1+len2; double[] union = new double[len]; if(len==0) return union; double last = 0; len1+=beg1; len2+=beg2; int beg=0; while(beg1<len1 && beg2<len2) { double val1 = ary1[beg1]; double val2 = ary2[beg2]; if(val1<val2) { if(beg==0||last<val1) last = union[beg++] = val1; beg1++; } else if(val1>val2) { if(beg==0||last<val2) last = union[beg++] = val2; beg2++; } else { if(beg==0||last<val1) last = union[beg++] = val1; beg1++; beg2++; } } while(beg1<len1) { double val1 = ary1[beg1]; if(beg==0||last<val1) last = union[beg++] = val1; beg1++; } while(beg2<len2) { double val2 = ary2[beg2]; if(beg==0||last<val2) last = union[beg++] = val2; beg2++; } if(beg>=len) return union; double[] copy = new double[beg]; System.arraycopy(union, 0, copy, 0, beg); return copy; } /** * Computes the union of segments in two sorted arrays, in descending order. * * @param ary1 the first sorted array * @param beg1 the start position of the first segment * @param len1 the length of the first segment * @param ary2 the second sorted array * @param beg2 the start position of the second segment * @param len2 the length of the second segment * @return the union of the two segments, with duplicates removed */ public static double[] unionDec(double[] ary1, int beg1, int len1, double[] ary2, int beg2, int len2) { int len = len1+len2; double[] union = new double[len]; if(len==0) return union; double last = 0; len1+=beg1; len2+=beg2; int beg=0; while(beg1<len1 && beg2<len2) { double val1 = ary1[beg1]; double val2 = ary2[beg2]; if(val1>val2) { if(beg==0||last>val1) last = union[beg++] = val1; beg1++; } else if(val1<val2) { if(beg==0||last>val1) last = union[beg++] = val2; beg2++; } else { if(beg==0||last>val1) last = union[beg++] = val1; beg1++; beg2++; } } while(beg1<len1) { double val1 = ary1[beg1]; if(beg==0||last>val1) last = union[beg++] = val1; beg1++; } while(beg2<len2) { double val2 = ary2[beg2]; if(beg==0||last>val2) last = union[beg++] = val2; beg2++; } if(beg>=len) return union; double[] copy = new double[beg]; System.arraycopy(union, 0, copy, 0, beg); return copy; } /** * Computes the intersection of segments in two sorted arrays, in ascending order. * * @param ary1 the first sorted array * @param beg1 the start position of the first segment * @param len1 the length of the first segment * @param ary2 the second sorted array * @param beg2 the start position of the second segment * @param len2 the length of the second segment * @return the intersection of the two segments, with duplicates removed */ public static double[] interInc(double[] ary1, int beg1, int len1, double[] ary2, int beg2, int len2) { int len = (len1>len2)?len1:len2; double[] inter = new double[len]; if(len==0) return inter; double last = 0; len1+=beg1; len2+=beg2; int beg=0; while(beg1<len1 && beg2<len2) { double val1 = ary1[beg1]; double val2 = ary2[beg2]; if(val1<val2) { beg1++; } else if(val1>val2) { beg2++; } else { if(beg==0||last<val1) last = inter[beg++] = val1; beg1++; beg2++; } } if(beg>=len) return inter; double[] copy = new double[beg]; System.arraycopy(inter, 0, copy, 0, beg); return copy; } /** * Computes the intersection of segments in two sorted arrays, in descending order. * * @param ary1 the first sorted array * @param beg1 the start position of the first segment * @param len1 the length of the first segment * @param ary2 the second sorted array * @param beg2 the start position of the second segment * @param len2 the length of the second segment * @return the intersection of the two segments, with duplicates removed */ public static double[] interDec(double[] ary1, int beg1, int len1, double[] ary2, int beg2, int len2) { int len = (len1>len2)?len1:len2; double[] inter = new double[len]; if(len==0) return inter; double last = 0; len1+=beg1; len2+=beg2; int beg=0; while(beg1<len1 && beg2<len2) { double val1 = ary1[beg1]; double val2 = ary2[beg2]; if(val1>val2) { beg1++; } else if(val1<val2) { beg2++; } else { if(beg==0||last>val1) last = inter[beg++] = val1; beg1++; beg2++; } } if(beg>=len) return inter; double[] copy = new double[beg]; System.arraycopy(inter, 0, copy, 0, beg); return copy; } /********************************************************************************* ** Copy and concatenation **/ /** * Append elements to an array. * * @param array the array to append to * @param elems the elements to append * * @return an array of doubles containing all the elements of {@code array} followed by all the elements in {@code elems} */ public static double[] append(double[] array, double... elems) { double[] concat=new double[array.length+elems.length]; System.arraycopy(array, 0, concat, 0, array.length); System.arraycopy(elems, 0, concat, array.length, elems.length); return concat; } /** * Prepend elements to an array. * * @param array the array to prepend to * @param elems the elements to prepend * * @return an array of doubles containing all the elements in {@code elems} followed by all the elements of {@code array} */ public static double[] prepend(double[] array, double... elems) { double[] concat=new double[array.length+elems.length]; System.arraycopy(elems, 0, concat, 0, elems.length); System.arraycopy(array, 0, concat, elems.length, array.length); return concat; } /** * Concatenates several arrays. * * @param array the first array to append to * @param arrays the arrays to append * * @return an array of doubles containing all the elements in the arrays, in order */ public static double[] concat(double[] array, double[]... arrays) { int l=array.length; for(double[] t : arrays) { l+=t.length; } double[] concat=new double[l]; System.arraycopy(array, 0, concat, 0, array.length); l=array.length; for(double[] t : arrays) { System.arraycopy(t, 0, concat, l, t.length); l+=t.length; } return concat; } /** * Returns a segment of an array. * * @param array the source array * @param beg the begining position of the segment, inclusive * @param end the ending position of the segment, exclusive * * @return an array of doubles, of length {@code end-beg}, and containing all the * elements between positions {@code beg}, inclusive, and {@code end}, exclusive, * of the original array */ public static double[] subarray(double[] array, int beg, int end) { int l=array.length; if(beg<0 || beg>end || end>l) throw new ArrayIndexOutOfBoundsException("["+beg+":"+end+"] is not a valid range specifier"); double[] subary=new double[end-beg]; if(end>beg) System.arraycopy(array, beg, subary, 0, end-beg); return subary; } /********************************************************************************* ** Container wrapping **/ /** * Returns an immutable container backed by an array. * * @param values the array of values for the container * @return a container holding the elements of the array, in order */ public static DoubleContainer container(final double... values) { return new DoubleContainer() { public long size() { return values==null?0:values.length; } public boolean isEmpty() { return values==null||values.length==0; } public DoubleIterator iterator() { return new DoubleIterator() { private volatile int pos = 0; public boolean hasNext() { return pos<values.length; } public Double next() { return nextValue(); } public double nextValue() { if(pos>=values.length) throw new NoSuchElementException(); return values[pos++]; } public void remove() { throw new UnsupportedOperationException(); } }; } public <Par> long visit(DoubleVisitor<Par> vis, Par par) { long ret = 0; if(values!=null) for(double val: values) { long r = vis.invoke(val, par); if(r<0) return ret; ret += r; } return ret; } public <Par> long visit(Visitor<Double,Par> vis, Par par) { long ret = 0; if(values!=null) for(double val: values) { long r = vis.invoke(val, par); if(r<0) return ret; ret += r; } return ret; } }; } /********************************************************************************* ** String transformation **/ /** * Builds a pretty string representation of a double array. * * @param buf the buffer to append the composed string to * @param array the double array to stringify * * @return the original buffer, for chaining purposes * * @throws java.io.IOException if the output buffer raises this exception on {@code append()} */ public static <A extends Appendable> A toString(A buf, double[] array) throws IOException { buf.append("[").append(Integer.toString(array.length)).append("|"); for(int i=0;i<array.length;i++) { if(i>0) buf.append(","); buf.append(String.format("%f", array[i])); } buf.append("]"); return buf; } /** * Builds a pretty string representation of a double array. * * @param buf the buffer to append the composed string to * @param array the double array to stringify * * @return the original buffer, for chaining purposes */ public static StringBuilder toString(StringBuilder buf, double[] array) { buf.append("[").append(array.length).append("|"); for(int i=0;i<array.length;i++) { if(i>0) buf.append(","); buf.append(String.format("%f", array[i])); } buf.append("]"); return buf; } /** * Returns a pretty string representation of a double array. * * @param array the double array to stringify * * @return a human-readable string exposing the contents of the array */ public static String toString(double[] array) { return toString(new StringBuilder(), array).toString(); } /** * Appends as strings the elements of a double array, separating them with a given string. * * @param buf the buffer to append the composed string to * @param sep the separator to use * @param array the double array to concatenate * * @return the original buffer, for chaining purposes * * @throws IOException if the output buffer raises this exception on {@code append()} */ public static <A extends Appendable> A join(A buf, String sep, double[] array) throws IOException { if(sep==null) for(int i=0;i<array.length;i++) { buf.append(String.format("%f", array[i])); } else for(int i=0;i<array.length;i++) { if(i>0) buf.append(sep); buf.append(String.format("%f", array[i])); } return buf; } /** * Appends as strings the elements of a double array, separating them with a given string. * * @param buf the buffer to append the composed string to * @param sep the separator to use * @param array the double array to concatenate * * @return a concatenation of the elements of the array, as string, and the separator */ public static StringBuilder join(StringBuilder buf, String sep, double[] array) { if(sep==null) for(int i=0;i<array.length;i++) { buf.append(String.format("%f", array[i])); } else for(int i=0;i<array.length;i++) { if(i>0) buf.append(sep); buf.append(String.format("%f", array[i])); } return buf; } /** * Appends as strings the elements of a double array, separating them with a given string. * * @param sep the separator to use * @param array the double array to concatenate * * @return a concatenation of the elements of the array, as string, and the separator */ public static String join(String sep, double[] array) { return join(new StringBuilder(), sep, array).toString(); } }