set = new TreeSet<>(comparator);
if (array == null || array.length == 0) return set;
for (E e : array) {
if (e == null) continue;
set.add(e);
}
return set;
}
public static Collection newSynchronizedCollection(Collection collection) {
return Collections.synchronizedCollection(collection);
}
public static Collection newUnmodifiableCollection(Collection collection) {
return Collections.unmodifiableCollection(collection);
}
/**
* Returns a {@link Collection} containing the union
* of the given {@link Collection}s.
*
* The cardinality of each element in the returned {@link Collection}
* will be equal to the maximum of the cardinality of that element
* in the two given {@link Collection}s.
*
* @param a the first collection
* @param b the second collection
* @return the union of the two collections
* @see Collection#addAll
*/
public static Collection union(final Collection a, final Collection b) {
if (a == null && b == null) return new ArrayList();
if (a == null) return new ArrayList(b);
if (b == null) return new ArrayList(a);
ArrayList list = new ArrayList<>();
Map mapA = getCardinalityMap(a);
Map mapB = getCardinalityMap(b);
Set elts = new HashSet(a);
elts.addAll(b);
for (Object obj : elts) {
for (int i = 0, m = Math.max(getFreq(obj, mapA), getFreq(obj, mapB)); i < m; i++) {
list.add(obj);
}
}
return list;
}
/**
* Returns a {@link Collection} containing the intersection
* of the given {@link Collection}s.
*
* The cardinality of each element in the returned {@link Collection}
* will be equal to the minimum of the cardinality of that element
* in the two given {@link Collection}s.
*
* @param a the first collection
* @param b the second collection
* @return the intersection of the two collections
* @see Collection#retainAll
*/
public static Collection intersection(final Collection a, final Collection b) {
if (a == null || b == null) return new ArrayList();
ArrayList list = new ArrayList<>();
Map mapA = getCardinalityMap(a);
Map mapB = getCardinalityMap(b);
Set elts = new HashSet(a);
elts.addAll(b);
for (Object obj : elts) {
for (int i = 0, m = Math.min(getFreq(obj, mapA), getFreq(obj, mapB)); i < m; i++) {
list.add(obj);
}
}
return list;
}
private static int getFreq(final Object obj, final Map freqMap) {
Integer count = (Integer) freqMap.get(obj);
if (count != null) {
return count;
}
return 0;
}
/**
* Returns a {@link Collection} containing the exclusive disjunction
* (symmetric difference) of the given {@link Collection}s.
*
* The cardinality of each element e in the returned {@link Collection}
* will be equal to
* max(cardinality(e ,a ),cardinality(e ,b )) - min(cardinality(e ,a ),cardinality(e ,b )) .
*
* This is equivalent to
* {@link #subtract subtract}({@link #union union(a,b)},{@link #intersection intersection(a,b)})
* or
* {@link #union union}({@link #subtract subtract(a,b)},{@link #subtract subtract(b,a)}) .
*
* @param a the first collection
* @param b the second collection
* @return the symmetric difference of the two collections
*/
public static Collection disjunction(final Collection a, final Collection b) {
if (a == null && b == null) return new ArrayList();
if (a == null) return new ArrayList(b);
if (b == null) return new ArrayList(a);
ArrayList list = new ArrayList<>();
Map mapA = getCardinalityMap(a);
Map mapB = getCardinalityMap(b);
Set elts = new HashSet(a);
elts.addAll(b);
for (Object obj : elts) {
for (int i = 0, m = ((Math.max(getFreq(obj, mapA), getFreq(obj, mapB)))
- (Math.min(getFreq(obj, mapA), getFreq(obj, mapB)))); i < m; i++) {
list.add(obj);
}
}
return list;
}
/**
* Returns a new {@link Collection} containing a - b .
* The cardinality of each element e in the returned {@link Collection}
* will be the cardinality of e in a minus the cardinality
* of e in b , or zero, whichever is greater.
*
* @param a the collection to subtract from
* @param b the collection to subtract
* @return a new collection with the results
* @see Collection#removeAll
*/
public static Collection subtract(final Collection a, final Collection b) {
if (a == null) return new ArrayList();
if (b == null) return new ArrayList(a);
ArrayList list = new ArrayList(a);
for (Object o : b) {
list.remove(o);
}
return list;
}
/**
* Returns true iff at least one element is in both collections.
*
* In other words, this method returns true iff the
* {@link #intersection} of coll1 and coll2 is not empty.
*
* @param coll1 the first collection
* @param coll2 the first collection
* @return true iff the intersection of the collections is non-empty
* @see #intersection
*/
public static boolean containsAny(final Collection coll1, final Collection coll2) {
if (coll1 == null || coll2 == null) return false;
if (coll1.size() < coll2.size()) {
for (Object o : coll1) {
if (coll2.contains(o)) {
return true;
}
}
} else {
for (Object o : coll2) {
if (coll1.contains(o)) {
return true;
}
}
}
return false;
}
/**
* Returns a {@link Map} mapping each unique element in the given
* {@link Collection} to an {@link Integer} representing the number
* of occurrences of that element in the {@link Collection}.
*
* Only those elements present in the collection will appear as
* keys in the map.
*
* @param coll the collection to get the cardinality map for, must not be null
* @return the populated cardinality map
*/
public static Map getCardinalityMap(final Collection coll) {
Map count = new HashMap<>();
if (coll == null) return count;
for (Object obj : coll) {
Integer c = count.get(obj);
if (c == null) {
count.put(obj, 1);
} else {
count.put(obj, c + 1);
}
}
return count;
}
/**
* Returns true iff a is a sub-collection of b ,
* that is, iff the cardinality of e in a is less
* than or equal to the cardinality of e in b ,
* for each element e in a .
*
* @param a the first (sub?) collection
* @param b the second (super?) collection
* @return true iff a is a sub-collection of b
* @see #isProperSubCollection
* @see Collection#containsAll
*/
public static boolean isSubCollection(final Collection a, final Collection b) {
if (a == null || b == null) return false;
Map mapA = getCardinalityMap(a);
Map mapB = getCardinalityMap(b);
for (Object obj : a) {
if (getFreq(obj, mapA) > getFreq(obj, mapB)) {
return false;
}
}
return true;
}
/**
* Returns true iff a is a proper sub-collection of b ,
* that is, iff the cardinality of e in a is less
* than or equal to the cardinality of e in b ,
* for each element e in a , and there is at least one
* element f such that the cardinality of f in b
* is strictly greater than the cardinality of f in a .
*
* The implementation assumes
*
* a.size() and b.size() represent the
* total cardinality of a and b , resp.
* a.size() < Integer.MAXVALUE
*
*
* @param a the first (sub?) collection
* @param b the second (super?) collection
* @return true iff a is a proper sub-collection of b
* @see #isSubCollection
* @see Collection#containsAll
*/
public static boolean isProperSubCollection(final Collection a, final Collection b) {
if (a == null || b == null) return false;
return a.size() < b.size() && isSubCollection(a, b);
}
/**
* Returns true iff the given {@link Collection}s contain
* exactly the same elements with exactly the same cardinalities.
*
* That is, iff the cardinality of e in a is
* equal to the cardinality of e in b ,
* for each element e in a or b .
*
* @param a the first collection
* @param b the second collection
* @return true iff the collections contain the same elements with the same cardinalities.
*/
public static boolean isEqualCollection(final Collection a, final Collection b) {
if (a == null || b == null) return false;
if (a.size() != b.size()) {
return false;
} else {
Map mapA = getCardinalityMap(a);
Map mapB = getCardinalityMap(b);
if (mapA.size() != mapB.size()) {
return false;
} else {
for (Object obj : mapA.keySet()) {
if (getFreq(obj, mapA) != getFreq(obj, mapB)) {
return false;
}
}
return true;
}
}
}
/**
* Returns the number of occurrences of obj in coll .
*
* @param obj the object to find the cardinality of
* @param coll the collection to search
* @return the the number of occurrences of obj in coll
*/
public static int cardinality(E obj, final Collection coll) {
if (coll == null) return 0;
if (coll instanceof Set) {
return (coll.contains(obj) ? 1 : 0);
}
int count = 0;
if (obj == null) {
for (E e : coll) {
if (e == null) {
count++;
}
}
} else {
for (E e : coll) {
if (obj.equals(e)) {
count++;
}
}
}
return count;
}
/**
* Finds the first element in the given collection which matches the given predicate.
*
* If the input collection or predicate is null, or no element of the collection
* matches the predicate, null is returned.
*
* @param collection the collection to search, may be null
* @param predicate the predicate to use, may be null
* @return the first element of the collection which matches the predicate or null if none could be found
*/
public static E find(Collection collection, Predicate predicate) {
if (collection == null || predicate == null) return null;
for (E item : collection) {
if (predicate.evaluate(item)) {
return item;
}
}
return null;
}
/**
* Executes the given closure on each element in the collection.
*
* If the input collection or closure is null, there is no change made.
*
* @param collection the collection to get the input from, may be null
* @param closure the closure to perform, may be null
*/
public static void forAllDo(Collection collection, Closure closure) {
if (collection == null || closure == null) return;
int index = 0;
for (E e : collection) {
closure.execute(index++, e);
}
}
/**
* Filter the collection by applying a Predicate to each element. If the
* predicate returns false, remove the element.
*
* If the input collection or predicate is null, there is no change made.
*
* @param collection the collection to get the input from, may be null
* @param predicate the predicate to use as a filter, may be null
*/
public static void filter(Collection collection, Predicate predicate) {
if (collection == null || predicate == null) return;
for (Iterator it = collection.iterator(); it.hasNext(); ) {
if (!predicate.evaluate((E) it.next())) {
it.remove();
}
}
}
/**
* Selects all elements from input collection which match the given predicate
* into an output collection.
*
* A null predicate matches no elements.
*
* @param inputCollection the collection to get the input from, may not be null
* @param predicate the predicate to use, may be null
* @return the elements matching the predicate (new list)
* @throws NullPointerException if the input collection is null
*/
public static Collection select(Collection inputCollection, Predicate predicate) {
if (inputCollection == null || predicate == null) return new ArrayList<>();
ArrayList answer = new ArrayList<>(inputCollection.size());
for (E o : inputCollection) {
if (predicate.evaluate(o)) {
answer.add(o);
}
}
return answer;
}
/**
* Selects all elements from inputCollection which don't match the given predicate
* into an output collection.
*
* If the input predicate is null, the result is an empty list.
*
* @param inputCollection the collection to get the input from, may not be null
* @param predicate the predicate to use, may be null
* @return the elements not matching the predicate (new list)
* @throws NullPointerException if the input collection is null
*/
public static Collection selectRejected(Collection inputCollection, Predicate predicate) {
if (inputCollection == null || predicate == null) return new ArrayList<>();
ArrayList answer = new ArrayList<>(inputCollection.size());
for (E o : inputCollection) {
if (!predicate.evaluate(o)) {
answer.add(o);
}
}
return answer;
}
/**
* Transform the collection by applying a Transformer to each element.
*
* If the input collection or transformer is null, there is no change made.
*
* This routine is best for Lists, for which set() is used to do the
* transformations "in place." For other Collections, clear() and addAll()
* are used to replace elements.
*
* If the input collection controls its input, such as a Set, and the
* Transformer creates duplicates (or are otherwise invalid), the
* collection may reduce in size due to calling this method.
*
* @param collection the collection to get the input from, may be null
* @param transformer the transformer to perform, may be null
*/
public static void transform(Collection collection, Transformer transformer) {
if (collection == null || transformer == null) return;
if (collection instanceof List) {
List list = (List) collection;
for (ListIterator it = list.listIterator(); it.hasNext(); ) {
it.set(transformer.transform((E1) it.next()));
}
} else {
Collection resultCollection = collect(collection, transformer);
collection.clear();
collection.addAll(resultCollection);
}
}
/**
* Returns a new Collection consisting of the elements of inputCollection transformed
* by the given transformer.
*
* If the input transformer is null, the result is an empty list.
*
* @param inputCollection the collection to get the input from, may be null
* @param transformer the transformer to use, may be null
* @return the transformed result (new list)
*/
public static Collection collect(final Collection inputCollection,
final Transformer transformer) {
List answer = new ArrayList<>();
if (inputCollection == null || transformer == null) return answer;
for (E1 e1 : inputCollection) {
answer.add(transformer.transform(e1));
}
return answer;
}
/**
* Counts the number of elements in the input collection that match the predicate.
*
* A null collection or predicate matches no elements.
*
* @param collection the collection to get the input from, may be null
* @param predicate the predicate to use, may be null
* @return the number of matches for the predicate in the collection
*/
public static int countMatches(Collection collection, Predicate predicate) {
if (collection == null || predicate == null) return 0;
int count = 0;
for (E o : collection) {
if (predicate.evaluate(o)) {
count++;
}
}
return count;
}
/**
* Answers true if a predicate is true for at least one element of a collection.
*
* A null collection or predicate returns false.
*
* @param collection the collection to get the input from, may be null
* @param predicate the predicate to use, may be null
* @return true if at least one element of the collection matches the predicate
*/
public static boolean exists(Collection collection, Predicate predicate) {
if (collection == null || predicate == null) return false;
for (E o : collection) {
if (predicate.evaluate(o)) {
return true;
}
}
return false;
}
/**
* Adds an element to the collection unless the element is null.
*
* @param collection the collection to add to, may be null
* @param object the object to add, if null it will not be added
* @return true if the collection changed
*/
public static boolean addIgnoreNull(Collection collection, E object) {
if (collection == null) return false;
return (object != null && collection.add(object));
}
/**
* Adds all elements in the iteration to the given collection.
*
* @param collection the collection to add to, may be null
* @param iterator the iterator of elements to add, may be null
*/
public static void addAll(Collection collection, Iterator iterator) {
if (collection == null || iterator == null) return;
while (iterator.hasNext()) {
collection.add(iterator.next());
}
}
/**
* Adds all elements in the enumeration to the given collection.
*
* @param collection the collection to add to, may be null
* @param enumeration the enumeration of elements to add, may be null
*/
public static void addAll(Collection collection, Enumeration enumeration) {
if (collection == null || enumeration == null) return;
while (enumeration.hasMoreElements()) {
collection.add(enumeration.nextElement());
}
}
/**
* Adds all elements in the array to the given collection.
*
* @param collection the collection to add to, may be null
* @param elements the array of elements to add, may be null
*/
public static void addAll(Collection collection, E[] elements) {
if (collection == null || elements == null || elements.length == 0) return;
collection.addAll(Arrays.asList(elements));
}
/**
* Returns the index-th value in object, throwing
* IndexOutOfBoundsException if there is no such element or
* IllegalArgumentException if object is not an
* instance of one of the supported types.
*
* The supported types, and associated semantics are:
*
* Map -- the value returned is the Map.Entry in position
* index in the map's entrySet iterator,
* if there is such an entry.
* List -- this method is equivalent to the list's get method.
* Array -- the index-th array entry is returned,
* if there is such an entry; otherwise an IndexOutOfBoundsException
* is thrown.
* Collection -- the value returned is the index-th object
* returned by the collection's default iterator, if there is such an element.
* Iterator or Enumeration -- the value returned is the
* index-th object in the Iterator/Enumeration, if there
* is such an element. The Iterator/Enumeration is advanced to
* index (or to the end, if index exceeds the
* number of entries) as a side effect of this method.
*
*
* @param object the object to get a value from
* @param index the index to get
* @return the object at the specified index
* @throws IndexOutOfBoundsException if the index is invalid
* @throws IllegalArgumentException if the object type is invalid
*/
public static Object get(Object object, int index) {
if (object == null) return null;
if (index < 0) {
throw new IndexOutOfBoundsException("Index cannot be negative: " + index);
}
if (object instanceof Map) {
Map map = (Map) object;
Iterator iterator = map.entrySet().iterator();
return get(iterator, index);
} else if (object instanceof List) {
return ((List) object).get(index);
} else if (object instanceof Object[]) {
return ((Object[]) object)[index];
} else if (object instanceof Iterator) {
Iterator it = (Iterator) object;
while (it.hasNext()) {
index--;
if (index == -1) {
return it.next();
} else {
it.next();
}
}
throw new IndexOutOfBoundsException("Entry does not exist: " + index);
} else if (object instanceof Collection) {
Iterator iterator = ((Collection) object).iterator();
return get(iterator, index);
} else if (object instanceof Enumeration) {
Enumeration it = (Enumeration) object;
while (it.hasMoreElements()) {
index--;
if (index == -1) {
return it.nextElement();
} else {
it.nextElement();
}
}
throw new IndexOutOfBoundsException("Entry does not exist: " + index);
} else {
try {
return Array.get(object, index);
} catch (IllegalArgumentException ex) {
throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
}
}
}
/**
* Gets the size of the collection/iterator specified.
*
* This method can handles objects as follows
*
* Collection - the collection size
* Map - the map size
* Array - the array size
* Iterator - the number of elements remaining in the iterator
* Enumeration - the number of elements remaining in the enumeration
*
*
* @param object the object to get the size of
* @return the size of the specified collection
* @throws IllegalArgumentException thrown if object is not recognised or null
*/
public static int size(Object object) {
if (object == null) return 0;
int total = 0;
if (object instanceof Map) {
total = ((Map) object).size();
} else if (object instanceof Collection) {
total = ((Collection) object).size();
} else if (object instanceof Object[]) {
total = ((Object[]) object).length;
} else if (object instanceof Iterator) {
Iterator it = (Iterator) object;
while (it.hasNext()) {
total++;
it.next();
}
} else if (object instanceof Enumeration) {
Enumeration it = (Enumeration) object;
while (it.hasMoreElements()) {
total++;
it.nextElement();
}
} else {
try {
total = Array.getLength(object);
} catch (IllegalArgumentException ex) {
throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
}
}
return total;
}
/**
* Checks if the specified collection/array/iterator is empty.
*
* This method can handles objects as follows
*
* Collection - via collection isEmpty
* Map - via map isEmpty
* Array - using array size
* Iterator - via hasNext
* Enumeration - via hasMoreElements
*
*
* Note: This method is named to avoid clashing with
* {@link #isEmpty(Collection)}.
*
* @param object the object to get the size of, not null
* @return true if empty
* @throws IllegalArgumentException thrown if object is not recognised or null
*/
public static boolean sizeIsEmpty(Object object) {
if (object == null) return true;
if (object instanceof Collection) {
return ((Collection) object).isEmpty();
} else if (object instanceof Map) {
return ((Map) object).isEmpty();
} else if (object instanceof Object[]) {
return ((Object[]) object).length == 0;
} else if (object instanceof Iterator) {
return !((Iterator) object).hasNext();
} else if (object instanceof Enumeration) {
return !((Enumeration) object).hasMoreElements();
} else {
try {
return Array.getLength(object) == 0;
} catch (IllegalArgumentException ex) {
throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
}
}
}
/**
* Null-safe check if the specified collection is empty.
*
* Null returns true.
*
* @param coll the collection to check, may be null
* @return true if empty or null
*/
public static boolean isEmpty(Collection coll) {
return coll == null || coll.size() == 0;
}
/**
* Null-safe check if the specified collection is not empty.
*
* Null returns false.
*
* @param coll the collection to check, may be null
* @return true if non-null and non-empty
*/
public static boolean isNotEmpty(Collection coll) {
return !isEmpty(coll);
}
/**
* Returns a collection containing all the elements in collection
* that are also in retain. The cardinality of an element e
* in the returned collection is the same as the cardinality of e
* in collection unless retain does not contain e, in which
* case the cardinality is zero. This method is useful if you do not wish to modify
* the collection c and thus cannot call c.retainAll(retain);.
*
* @param collection the collection whose contents are the target of the #retailAll operation
* @param retain the collection containing the elements to be retained in the returned collection
* @return a Collection containing all the elements of collection
* that occur at least once in retain.
*/
public static Collection retainAll(Collection collection, Collection retain) {
if (collection == null || retain == null) return new ArrayList<>();
List list = new ArrayList<>();
for (E item : collection) {
if (retain.contains(item)) {
list.add(item);
}
}
return list;
}
/**
* Removes the elements in remove from collection. That is, this
* method returns a collection containing all the elements in c
* that are not in remove. The cardinality of an element e
* in the returned collection is the same as the cardinality of e
* in collection unless remove contains e, in which
* case the cardinality is zero. This method is useful if you do not wish to modify
* the collection c and thus cannot call collection.removeAll(remove);.
*
* @param collection the collection from which items are removed (in the returned collection)
* @param remove the items to be removed from the returned collection
* @return a Collection containing all the elements of collection except
* any elements that also occur in remove.
*/
public static Collection removeAll(Collection collection, Collection remove) {
if (collection == null) return new ArrayList<>();
if (remove == null) return new ArrayList<>(collection);
List list = new ArrayList<>();
for (E obj : collection) {
if (!remove.contains(obj)) {
list.add(obj);
}
}
return list;
}
/**
* Randomly permutes the specified list using a default source of randomness.
*
* @param list the list to be shuffled.
* @throws UnsupportedOperationException if the specified list or
* its list-iterator does not support the set operation.
*/
public static void shuffle(List list) {
Collections.shuffle(list);
}
/**
* Return the string of collection.
*
* @param collection The collection.
* @return the string of collection
*/
public static String toString(Collection collection) {
if (collection == null) return "null";
return collection.toString();
}
public interface Closure {
void execute(int index, E item);
}
public interface Transformer {
E2 transform(E1 input);
}
public interface Predicate {
boolean evaluate(E item);
}
}