/**
*
*/
package net.varkhan.base.containers.array;
import net.varkhan.base.containers.Iterator;
import net.varkhan.base.containers.list.List;
import net.varkhan.base.containers.map.ArrayOpenHashMap;
import net.varkhan.base.containers.map.Map;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Comparator;
import java.util.NoSuchElementException;
/**
* <b>Static array manipulation utilities.</b>
* <p/>
* Utilities for converting primitive type arrays to human-readable strings,
* accessing, comparing and sorting array elements.
* <p/>
*
* @author varkhan
* @date Mar 12, 2009
* @time 2:52:53 AM
*/
public class Arrays {
/**
* Private empty constructor that forbids instantiation of this class.
*/
protected Arrays() {
}
/*********************************************************************************
** Matching operations
**/
/**
* Indicates whether two byte arrays are equal.
*
* @param array1 the first array
* @param array2 the second array
* @param <T> the element type
*
* @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 <T> boolean equals(T[] array1, T[] 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]) continue;
if(array1[i]==null&&array2[i]!=null) return false;
if(array1[i]!=null&&array2[i]==null) return false;
if(!array1[i].equals(array2[i])) return false;
}
return true;
}
/**
* Returns the position of the first occurrence of an object inside an array.
*
* @param item the object to search for
* @param array the array to search
* @param <T> the element type
*
* @return {@literal -1} if {@code item} was not found in {@code array},
* the position of the first element of the array for which {@code item}.{@link Object#equals(Object) equals}() is true.
*/
public static <T> int indexOf(T item, T... array) {
if(array==null) return -1;
final int length=array.length;
if(item==null) {
for(int i=0;i<length;i++) {
if(array[i]==null) return i;
}
return -1;
}
else {
for(int i=0;i<length;i++) {
if(item.equals(array[i])) return i;
}
return -1;
}
}
/**
* Returns the position of the first occurrence of an array as a subsequence
* of an other array.
*
* @param array the array
* @param pos the starting point in the array
* @param sub the subsequence to find
* @param <T> the element type
*
* @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 <T> int indexOf(T[] array, int pos, T[] sub) {
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;
T a=array[pos+i];
T s=sub[i];
if(a==s) continue;
if((a==null)||(s==null)||!a.equals(s)
) {
pos++;
continue match;
}
}
return pos;
}
return -1;
}
/*********************************************************************************
** Sorting and search
**/
/**
* Sorts an array in place using the natural order.
*
* @param ary the array to sort
* @param <T> the element type
* @return the number of swap operations required for the sorting
*/
public static <T extends Comparable<? super T>> int sort(T... ary) {
return sort(ary, 0, ary.length-1);
}
/**
* Sorts an array segment in place using the natural order.
*
* @param ary the array to sort
* @param inf the minimum index
* @param sup the maximum index
* @param <T> the element type
* @return the number of swap operations required for the sorting
*/
public static <T extends Comparable<? super T>> int sort(T[] 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 += heapDown(ary,beg,sup);
}
int end = sup;
while(end>=inf) {
T v = ary[end];
ary[end] = ary[inf];
ary[inf] = v;
end --;
cnt += 1 + heapDown(ary,inf,end);
}
return cnt;
}
protected static <T extends Comparable<? super T>> int heapDown(T[] ary, int inf, int sup) {
int cnt = 0;
int pos = inf;
int cld = (pos<<1)+1;
while(cld<=sup) {
int swp = pos;
int cmp = ary[swp].compareTo(ary[cld]);
if(cmp<0) swp = cld;
cld ++;
if(cld<=sup) {
cmp = ary[swp].compareTo(ary[cld]);
if(cmp<0) swp = cld;
}
if(swp==pos) return cnt;
T v = ary[pos];
ary[pos] = ary[swp];
ary[swp] = v;
cnt ++;
pos = swp;
cld = (pos<<1)+1;
}
return cnt;
}
/**
* Sorts an array in place using a comparator.
*
*
* @param comp the comparator
* @param ary the array to sort
* @return the number of swap operations required for the sorting
*/
public static <T> int sort(Comparator<? super T> comp, T... ary) {
return sort(comp, ary, 0, ary.length-1);
}
/**
* Sorts an array segment in place using a comparator.
*
*
* @param comp the comparator
* @param ary the array to sort
* @param inf the minimum index
* @param sup the maximum index
* @param <T> the element type
* @return the number of swap operations required for the sorting
*/
public static <T> int sort(Comparator<? super T> comp, T[] 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 += heapDown(comp, ary,beg,sup);
}
int end = sup;
while(end>=inf) {
T v = ary[end];
ary[end] = ary[inf];
ary[inf] = v;
end --;
cnt += 1 + heapDown(comp, ary,inf,end);
}
return cnt;
}
protected static <T> int heapDown(Comparator<? super T> comp, T[] ary, int inf, int sup) {
int cnt = 0;
int pos = inf;
int cld = (pos<<1)+1;
while(cld<=sup) {
int swp = pos;
int cmp = comp.compare(ary[swp], ary[cld]);
if(cmp<0) swp = cld;
cld ++;
if(cld<=sup) {
cmp = comp.compare(ary[swp], ary[cld]);
if(cmp<0) swp = cld;
}
if(swp==pos) return cnt;
T 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, using the natural order.
*
* @param ary the sorted array
* @param inf the minimum index
* @param sup the maximum index
* @param key the object to search for
* @param <T> the element type
*
* @return the key position in the array, or {@code -(inspos+1)},
* where {@code inspos} is the index of the first object in the
* array bigger than {@code key}
*/
public static <T extends Comparable<? super T>> int search(T[] ary, int inf, int sup, T key) {
int min=inf;
int max=sup;
while(min<max) {
int med=(min+max)>>>1;
T medVal=ary[med];
int cmp=medVal.compareTo(key);
if(cmp<0) min=med+1;
else if(cmp>0) max=med-1;
else return med; // key found
}
return -(min+1); // key not found.
}
/**
* Finds an object in a sorted array, using a comparator.
*
* @param ary the sorted array
* @param inf the minimum index
* @param sup the maximum index
* @param key the object to search for
* @param comp the comparator
* @param <T> the element type
*
* @return the key position in the array, or {@code -(inspos+1)},
* where {@code inspos} is the index of the first object in the
* array bigger than {@code key}
*/
public static <T> int search(T[] ary, int inf, int sup, T key, Comparator<? super T> comp) {
// if (comp == null) return search(ary, inf, sup, key);
int min=inf;
int max=sup;
while(min<max) {
int med=(min+max)>>>1;
T medVal=ary[med];
int cmp=comp.compare(medVal, key);
if(cmp<0) min=med+1;
else if(cmp>0) max=med-1;
else return med; // key found
}
return -(min+1); // key not found.
}
/**
* Inserts an object in a sorted array, using the natural order.
* The array <em>must</em> have space for an extra element, i.e.
* the length of the array must be larger than the specified
* maximum index.
*
* @param ary the sorted array
* @param inf the minimum index
* @param sup the maximum index
* @param key the object to insert
* @param <T> the element type
*
* @return the position of the inserted object
* @throws ArrayIndexOutOfBoundsException if sup <= ary.length
*/
public static <T extends Comparable<? super T>> int insert(T[] ary, int inf, int sup, T key) {
int min=inf;
int max=sup;
while(min<max) {
int med=(min+max)>>>1;
T medVal=ary[med];
int cmp=medVal.compareTo(key);
if(cmp<0) min=med+1;
else if(cmp>0) max=med-1;
else {
System.arraycopy(ary, med, ary, med+1, sup-med-1);
ary[med]=key;
return med;
}
}
if(min<sup) System.arraycopy(ary, min, ary, min+1, sup-min);
ary[min]=key;
return min;
}
/**
* Inserts an object in a sorted array, using a comparator.
* The array <em>must</em> have space for an extra element, i.e.
* the length of the array must be larger than the specified
* maximum index.
*
* @param ary the sorted array
* @param inf the minimum index
* @param sup the maximum index
* @param key the object to insert
* @param comp the comparator
* @param <T> the element type
*
* @return the position of the inserted object
* @throws ArrayIndexOutOfBoundsException if sup <= ary.length
*/
public static <T> int insert(T[] ary, int inf, int sup, T key, Comparator<? super T> comp) {
// if (comp == null) return insert(ary, inf, sup, key);
int min=inf;
int max=sup;
while(min<max) {
int med=(min+max)>>>1;
T medVal=ary[med];
int cmp=comp.compare(medVal, key);
if(cmp<0) min=med+1;
else if(cmp>0) max=med-1;
else {
System.arraycopy(ary, med, ary, med+1, sup-med-1);
ary[med]=key;
return med;
}
}
if(min<sup) System.arraycopy(ary, min, ary, min+1, sup-min);
ary[min]=key;
return min;
}
/**
* Computes the union of segments in two sorted arrays, using a comparator.
*
* @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
* @param comp the comparator
* @param <T> the element type
* @return the union of the two segments, with duplicates removed
*/
public static <T> T[] union(T[] ary1, int beg1, int len1, T[] ary2, int beg2, int len2, Comparator<? super T> comp) {
int len = len1+len2;
@SuppressWarnings("unchecked")
T[] union=(ary1.getClass()==Object[].class)
? (T[]) new Object[len]
: (T[]) Array.newInstance(ary1.getClass().getComponentType(), len);
if(len==0) return union;
T last = null;
len1+=beg1;
len2+=beg2;
int beg=0;
while(beg1<len1 && beg2<len2) {
T val1 = ary1[beg1];
T val2 = ary2[beg2];
int cmp = comp.compare(val1, val2);
if(cmp<0) { if(beg==0||comp.compare(val1,last)>0) last = union[beg++] = val1; beg1++; } else
if(cmp>0) { if(beg==0||comp.compare(val2,last)>0) last = union[beg++] = val2; beg2++; } else
{ if(beg==0||comp.compare(val1,last)>0) last = union[beg++] = val1; beg1++; beg2++; }
}
while(beg1<len1) {
T val1 = ary1[beg1];
if(beg==0||comp.compare(val1,last)>0) last = union[beg++] = val1;
beg1++;
}
while(beg2<len2) {
T val2 = ary2[beg2];
if(beg==0||comp.compare(val2,last)>0) last = union[beg++] = val2;
beg2++;
}
if(beg==len) return union;
@SuppressWarnings("unchecked")
T[] copy = (((Object) ary1.getClass())==Object[].class)
? (T[]) new Object[len]
: (T[]) Array.newInstance(ary1.getClass().getComponentType(), beg);
System.arraycopy(union, 0, copy, 0, beg);
return copy;
}
/**
* Computes the union of segments in two sorted arrays, using the natural 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
* @param <T> the element type
* @return the union of the two segments, with duplicates removed
*/
public static <T extends Comparable<? super T>> T[] union(T[] ary1, int beg1, int len1, T[] ary2, int beg2, int len2) {
int len = len1+len2;
@SuppressWarnings("unchecked")
T[] union=(((Object) ary1.getClass())==Object[].class)
? (T[]) new Object[len]
: (T[]) Array.newInstance(ary1.getClass().getComponentType(), len);
if(len==0) return union;
T last = null;
len1+=beg1;
len2+=beg2;
int beg=0;
while(beg1<len1 && beg2<len2) {
T val1 = ary1[beg1];
T val2 = ary2[beg2];
int cmp = val1.compareTo(val2);
if(cmp<0) { if(beg==0||val1.compareTo(last)>0) last = union[beg++] = val1; beg1++; } else
if(cmp>0) { if(beg==0||val2.compareTo(last)>0) last = union[beg++] = val2; beg2++; } else
{ if(beg==0||val1.compareTo(last)>0) last = union[beg++] = val1; beg1++; beg2++; }
}
while(beg1<len1) {
T val1 = ary1[beg1];
if(beg==0||val1.compareTo(last)>0) last = union[beg++] = val1;
beg1++;
}
while(beg2<len2) {
T val2 = ary2[beg2];
if(beg==0||val2.compareTo(last)>0) last = union[beg++] = val2;
beg2++;
}
if(beg==len) return union;
@SuppressWarnings("unchecked")
T[] copy = (((Object) ary1.getClass())==Object[].class)
? (T[]) new Object[len]
: (T[]) Array.newInstance(ary1.getClass().getComponentType(), beg);
System.arraycopy(union, 0, copy, 0, beg);
return copy;
}
/**
* Computes the intersection of segments in two sorted arrays, using a comparator.
*
* @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
* @param comp the comparator
* @param <T> the element type
* @return the intersection of the two segments, with duplicates removed
*/
public static <T> T[] inter(T[] ary1, int beg1, int len1, T[] ary2, int beg2, int len2, Comparator<? super T> comp) {
int len = (len1>len2)?len1:len2;
@SuppressWarnings("unchecked")
T[] inter=(ary1.getClass()==Object[].class)
? (T[]) new Object[len]
: (T[]) Array.newInstance(ary1.getClass().getComponentType(), len);
if(len==0) return inter;
T last = null;
len1+=beg1;
len2+=beg2;
int beg=0;
while(beg1<len1 && beg2<len2) {
T val1 = ary1[beg1];
T val2 = ary2[beg2];
int cmp = comp.compare(val1, val2);
if(cmp<0) { beg1++; } else
if(cmp>0) { beg2++; } else
{ beg1++; beg2++; if(beg==0||comp.compare(val1,last)>0) last = inter[beg++] = val1;}
}
if(beg==len) return inter;
@SuppressWarnings("unchecked")
T[] copy = (((Object) ary1.getClass())==Object[].class)
? (T[]) new Object[len]
: (T[]) Array.newInstance(ary1.getClass().getComponentType(), beg);
System.arraycopy(inter, 0, copy, 0, beg);
return copy;
}
/**
* Computes the intersection of segments in two sorted arrays, using the natural 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
* @param <T> the element type
* @return the intersection of the two segments, with duplicates removed
*/
public static <T extends Comparable<? super T>> T[] inter(T[] ary1, int beg1, int len1, T[] ary2, int beg2, int len2) {
int len = (len1>len2)?len1:len2;
@SuppressWarnings("unchecked")
T[] inter=(((Object)ary1.getClass())==Object[].class)
? (T[]) new Object[len]
: (T[]) Array.newInstance(ary1.getClass().getComponentType(), len);
if(len==0) return inter;
T last = null;
len1+=beg1;
len2+=beg2;
int beg=0;
while(beg1<len1 && beg2<len2) {
T val1 = ary1[beg1];
T val2 = ary2[beg2];
int cmp = val1.compareTo(val2);
if(cmp<0) { beg1++; } else
if(cmp>0) { beg2++; } else
{ beg1++; beg2++; if(beg==0||val1.compareTo(last)>0) last = inter[beg++] = val1;}
}
if(beg==len) return inter;
@SuppressWarnings("unchecked")
T[] copy = (((Object) ary1.getClass())==Object[].class)
? (T[]) new Object[len]
: (T[]) Array.newInstance(ary1.getClass().getComponentType(), 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
* @param <T> the element type
*
* @return an array containing all the elements of {@code array} followed by all the elements in {@code elems}
*/
public static <T> T[] append(T[] array, T... elems) {
@SuppressWarnings("unchecked")
T[] concat=(array.getClass()==Object[].class)
? (T[]) new Object[array.length+elems.length]
: (T[]) Array.newInstance(array.getClass().getComponentType(), 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
* @param <T> the element type
*
* @return an array containing all the elements in {@code elems} followed by all the elements of {@code array}
*/
public static <T> T[] prepend(T[] array, T... elems) {
@SuppressWarnings("unchecked")
T[] concat=(array.getClass()==Object[].class)
? (T[]) new Object[array.length+elems.length]
: (T[]) Array.newInstance(array.getClass().getComponentType(), 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
* @param <T> the element type
*
* @return an array whose element type is the element type of the first array, and containing all the elements in the arrays, in order
*/
public static <T> T[] concat(T[] array, T[]... arrays) {
int l=array.length;
for(T[] t : arrays) { l+=t.length; }
java.util.Arrays.copyOf(array, 0);
@SuppressWarnings("unchecked")
T[] concat=(array.getClass()==Object[].class)
? (T[]) new Object[l]
: (T[]) Array.newInstance(array.getClass().getComponentType(), l);
System.arraycopy(array, 0, concat, 0, array.length);
l=array.length;
for(T[] 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 beginning position of the segment, inclusive
* @param end the ending position of the segment, exclusive
* @param <T> the element type
*
* @return an array whose element type is the element type of the input array, 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 <T> T[] subarray(T[] 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");
@SuppressWarnings("unchecked")
T[] subary=(array.getClass()==Object[].class)
? (T[]) new Object[end-beg]
: (T[]) Array.newInstance(array.getClass().getComponentType(), end-beg);
if(end>beg) System.arraycopy(array, beg, subary, 0, end-beg);
return subary;
}
/*********************************************************************************
** Container wrapping
**/
/**
* Returns an immutable list backed by an array.
*
* @param values the array of values
* @param <T> the type of the values
* @return a list holding the elements of the array, in order
*/
public static <T> List<T> asList(final T... values) {
if(values==null) return new _List<T>(null,0,0);
return new _List<T>(values.clone(),0,values.length);
}
protected static class _List<T> implements List<T> {
private final int beg;
private final int len;
private final T[] vals;
public _List(T[] vals, int beg, int len) {
this.vals=vals;
this.beg=beg;
this.len=len;
}
public long size() { return vals==null?0:len; }
public boolean isEmpty() { return vals==null||len==0; }
public void clear() { }
public boolean add(T elt) { return false; }
public boolean add(long idx, T elt) { return false; }
public T get(long idx) { return vals==null||idx<0||idx>=len ? null : vals[beg+(int)idx]; }
public boolean set(long idx, T elt) {
if(vals==null) return false;
if(0<=idx && idx<len && vals[beg+(int)idx]!=elt) {
vals[beg+(int)idx]=elt;
return true;
}
else return false;
}
public boolean del(long idx) { return false; }
public boolean del(T elt) { return false; }
public Iterator<? extends T> iterator() {
return new Iterator<T>() {
private volatile int pos=0;
public boolean hasNext() { return vals!=null&&pos<len; }
public T next() {
if(vals==null||pos>=len) throw new NoSuchElementException();
return vals[beg+pos++];
}
public void remove() { throw new UnsupportedOperationException(); }
};
}
public <Par> long visit(Visitor<T,Par> vis, Par par) {
long ret=0;
if(vals!=null) for(int i=0;i<len;i++) {
T obj=vals[beg+i];
long r=vis.invoke(obj, par);
if(r<0) return ret;
ret+=r;
}
return ret;
}
public List<T> sublist(long beg, long end) {
return new _List<T>(vals,(int)(this.beg+beg),(int)(end-beg));
}
public String toString() {
StringBuilder buf=new StringBuilder();
buf.append('[');
boolean first = true;
for(int i=0;i<len;i++) {
T obj=vals[beg+i];
if(first) first=false;
else buf.append(',');
buf.append(' ').append(obj);
i++;
}
buf.append(' ').append(']');
return buf.toString();
}
public int hashCode() {
int hash=0;
hash^=len;
if(len>0) {
for(int i=0;i<len;i++) {
Object o=vals[beg+i];
if(o!=null) hash^=o.hashCode();
}
}
return hash;
}
public boolean equals(Object obj) {
if(!(obj instanceof List)) return false;
List<?> that=(List<?>) obj;
if(vals==null) return that.size()==0;
if(len!=that.size()) return false;
if(len>0) {
for(int i=0;i<len;i++) {
Object thiso=vals[beg+i];
Object thato=that.get(i);
if(thiso==thato) continue;
if(thiso==null||thato==null) return false;
if(!thiso.equals(thato)) return false;
}
}
return true;
}
}
/**
* Returns an array of alternating keys and values as a map.
*
* @param kclass the class of the keys
* @param vclass the class of the values
* @param values the array of keys and values
* @param <K> the type of the keys
* @param <V> the type of the values
* @return a map associating the object at even indexes in the array to the immediately following (odd index) element
*/
@SuppressWarnings({ "unchecked" })
public static <K, V> Map<K,V> asMap(final Class<K> kclass, final Class<V> vclass, final Object... values) {
ArrayOpenHashMap<K,V> map=new ArrayOpenHashMap<K,V>();
if(values==null) return map;
if((values.length&1)!=0) throw new IllegalArgumentException("Key/Value array must be of even size");
for(int i=0;i<values.length;i+=2) {
Object key=values[i];
if(key!=null&&!kclass.isAssignableFrom(key.getClass()))
throw new IllegalArgumentException("Invalid key type at "+i);
Object val=values[i+1];
if(val!=null&&!vclass.isAssignableFrom(val.getClass()))
throw new IllegalArgumentException("Invalid value type at "+(i+1));
map.add((K) key, (V) val);
}
return map;
}
/*********************************************************************************
** String transformation
**/
/**
* Builds a pretty string representation of an array.
*
* @param buf the buffer to append the composed string to
* @param array the array to stringify
* @param <T> the element type
* @param <A> the buffer type
*
* @return the original buffer, for chaining purposes
*
* @throws java.io.IOException if the output buffer raises this exception on {@code append()}
*/
public static <T, A extends Appendable> A toString(A buf, T... array) throws IOException {
buf.append("[").append(Integer.toString(array.length)).append("|");
for(int i=0;i<array.length;i++) {
if(i>0) buf.append(",");
T t=array[i];
if(t!=null) buf.append(t.toString());
}
buf.append("]");
return buf;
}
/**
* Builds a pretty string representation of an array.
*
* @param buf the buffer to append the composed string to
* @param array the array to stringify
* @param <T> the element type
*
* @return the original buffer, for chaining purposes
*/
public static <T> StringBuilder toString(StringBuilder buf, T... array) {
buf.append("[").append(array.length).append("|");
for(int i=0;i<array.length;i++) {
if(i>0) buf.append(",");
T t=array[i];
if(t!=null) buf.append(t.toString());
}
buf.append("]");
return buf;
}
/**
* Returns a pretty string representation of an array.
*
* @param array the array to stringify
* @param <T> the element type
*
* @return a human-readable string exposing the contents of the array
*/
public static <T> String toString(T... array) {
StringBuilder buf=new StringBuilder();
return toString(buf, array).toString();
}
/**
* Appends as strings the elements of an array, wrapping each non-null
* element with delimiters and separating them with a given string.
*
* @param buf the buffer to append the composed string to
* @param sep the separator between elements
* @param ldl the left delimiter of elements
* @param rdl the right delimiter of element
* @param array the array to join
* @param <T> the element type
* @param <A> the buffer type
*
* @return the original buffer, for chaining purposes
*
* @throws IOException if the output buffer raises this exception on {@code append()}
*/
public static <T, A extends Appendable> A join(A buf, String sep, String ldl, String rdl, T... array) throws IOException {
if(sep==null) for(int i=0;i<array.length;i++) {
T elt=array[i];
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
buf.append(elt.toString());
if(rdl!=null) buf.append(rdl);
}
}
else for(int i=0;i<array.length;i++) {
if(i>0) buf.append(sep);
T elt=array[i];
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
buf.append(elt.toString());
if(rdl!=null) buf.append(rdl);
}
}
return buf;
}
/**
* Appends as strings the elements of an array, wrapping each non-null
* element with delimiters and separating them with a given string.
*
* @param buf the buffer to append the composed string to
* @param sep the separator between elements
* @param ldl the left delimiter of elements
* @param rdl the right delimiter of element
* @param array the array to join
* @param <T> the element type
*
* @return the original buffer, for chaining purposes
*/
public static <T> StringBuilder join(StringBuilder buf, String sep, String ldl, String rdl, T... array) {
if(sep==null) for(int i=0;i<array.length;i++) {
T elt=array[i];
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
buf.append(elt.toString());
if(rdl!=null) buf.append(rdl);
}
}
else for(int i=0;i<array.length;i++) {
if(i>0) buf.append(sep);
T elt=array[i];
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
buf.append(elt.toString());
if(rdl!=null) buf.append(rdl);
}
}
return buf;
}
/**
* Appends as strings the elements of an array, wrapping each non-null
* element with delimiters and separating them with a given string.
*
* @param sep the separator between elements
* @param ldl the left delimiter of elements
* @param rdl the right delimiter of element
* @param array the array to join
* @param <T> the element type
*
* @return a concatenation of the elements of the array, as strings wrapped in the delimiters, and the separator
*/
public static <T> String join(String sep, String ldl, String rdl, T... array) {
return join(new StringBuilder(), sep, ldl, rdl, array).toString();
}
/**
* Appends as strings the elements of an array, separating them with a given string.
*
* @param sep the separator between elements
* @param array the array to join
* @param <T> the element type
*
* @return a concatenation of the elements of the array, as strings, and the separator
*/
public static <T> String join(String sep, T... array) {
return join(new StringBuilder(), sep, null, null, array).toString();
}
}