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

org.kuali.common.util.CollectionUtils Maven / Gradle / Ivy

There is a newer version: 4.4.17
Show newest version
/**
 * Copyright 2010-2014 The Kuali Foundation
 *
 * Licensed under the Educational Community License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.opensource.org/licenses/ecl2.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.kuali.common.util;

import static com.google.common.collect.Lists.newArrayList;
import static org.apache.commons.lang3.StringUtils.isBlank;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.kuali.common.util.nullify.NullUtils;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;

public class CollectionUtils {

	private enum BlanksFilter implements Predicate {
		INSTANCE;
		@Override
		public boolean apply(String input) {
			return isBlank(input);
		}
	}

	public static boolean hasBlanks(Collection collection) {
		return !getBlanks(collection).isEmpty();
	}

	public static Collection getBlanks(Collection collection) {
		return newArrayList(Iterables.filter(collection, BlanksFilter.INSTANCE));
	}

	/**
	 * Returns a new unmodifiable list containing the elements from list
	 * 
	 * @deprecated See ListUtils.newArrayList() instead
	 */
	@Deprecated
	public static  List unmodifiableCopy(List list) {
		return Collections.unmodifiableList(new ArrayList(list));
	}

	/**
	 * Get an unmodifiable list from the single element. Return emptyList() if element is null.
	 * 
	 * @deprecated Use CollectionUtils.singletonList() instead
	 */
	@Deprecated
	public static  List unmodifiableList(T element) {
		List list = toEmptyList(element);
		return Collections.unmodifiableList(list);
	}

	/**
	 * Get an unmodifiable list from elements
	 * 
	 * @deprecated Use ImmutableList.copyOf(elements) instead
	 */
	@Deprecated
	@SafeVarargs
	public static  List unmodifiableList(T... elements) {
		return Collections.unmodifiableList(Arrays.asList(elements));
	}

	/**
	 * If the CSV is whitespace, the empty string, null, "null", or "none", return an empty list.
	 */
	public static List getNoneSensitiveListFromCSV(String csv) {
		if (StringUtils.isBlank(csv) || NullUtils.isNullOrNone(csv)) {
			return Collections. emptyList();
		} else {
			return CollectionUtils.getTrimmedListFromCSV(csv);
		}
	}

	/**
	 * Remove any Strings from the list that do not match the filter and then sort the ones that remain
	 * 
	 * @return The list of strings that were filtered out.
	 * @deprecated
	 */
	@Deprecated
	public static List filterAndSort(List strings, StringFilter filter) {
		List excluded = filter(strings, filter);
		Collections.sort(strings);
		return excluded;
	}

	/**
	 * Remove any Strings from the list that do not match the filter and then sort the ones that remain
	 * 
	 * @return The list of strings that were filtered out.
	 */
	public static List filterAndSortStrings(List strings, org.kuali.common.util.filter.StringFilter filter) {
		List excluded = filterStrings(strings, filter);
		Collections.sort(strings);
		return excluded;
	}

	/**
	 * Remove any Strings from the collection that do not match the filter
	 */
	public static List filterStrings(Collection strings, org.kuali.common.util.filter.StringFilter filter) {
		List excluded = new ArrayList();
		Iterator itr = strings.iterator();
		while (itr.hasNext()) {
			String string = itr.next();
			if (!filter.include(string)) {
				excluded.add(string);
				itr.remove();
			}
		}
		return excluded;
	}

	/**
	 * Remove any Strings from the collection that do not match the filter
	 * 
	 * @deprecated
	 */
	@Deprecated
	public static List filter(Collection strings, StringFilter filter) {
		List excluded = new ArrayList();
		Iterator itr = strings.iterator();
		while (itr.hasNext()) {
			String string = itr.next();
			if (!filter.include(string)) {
				excluded.add(string);
				itr.remove();
			}
		}
		return excluded;
	}

	/**
	 * Null safe method for converting an array of objects into a list. Never returns null.
	 */
	public static List asList(Object... objects) {
		List list = new ArrayList();
		if (objects == null) {
			return list;
		}
		for (Object element : objects) {
			if (element != null) {
				list.add(element);
			}
		}
		return list;
	}

	/**
	 * Null safe method for converting an untyped array of classes into a list. Never returns null.
	 */
	public static List> asList(Class... classes) {
		List> list = new ArrayList>();
		if (classes == null) {
			return list;
		}
		for (Class element : classes) {
			if (element != null) {
				list.add(element);
			}
		}
		return list;
	}

	/**
	 * Return an array of int's that represents as even of a split as possible
	 * 
	 * For example: passing in 100,7 returns 15, 15, 14, 14, 14, 14, 14
	 * 
	 * @param numerator
	 * @param denominator
	 * @return
	 */
	public static int[] getDivideEvenly(int number, int howManyWays) {
		Assert.isTrue(howManyWays > 0, "howManyWays must be a positive integer");
		int quotient = number / howManyWays;
		int remainder = number % howManyWays;

		int[] lengths = new int[howManyWays];
		for (int i = 0; i < howManyWays; i++) {
			int length = i < remainder ? quotient + 1 : quotient;
			lengths[i] = length;
		}
		return lengths;
	}

	/**
	 * Split elements evenly into separate lists divided up howManyWays
	 */
	public static final  List> splitEvenly(List elements, int howManyWays) {
		// Can't split 2 things 3 ways
		if (howManyWays > elements.size()) {
			howManyWays = elements.size();
		}
		int[] lengths = getDivideEvenly(elements.size(), howManyWays);
		int offset = 0;
		List> listOfLists = new ArrayList>();
		for (int i = 0; i < lengths.length; i++) {
			int length = lengths[i];
			List sublist = new ArrayList();
			for (int j = offset; j < offset + length; j++) {
				sublist.add(elements.get(j));
			}
			listOfLists.add(sublist);
			offset += length;
		}
		return listOfLists;
	}

	/**
	 * Prefix the strings passed in with their position in the list (left padded with zero's). The padding is the number of digits in the size of the list. A list with 100 elements
	 * will return strings prefixed with 000, 001, etc.
	 */
	public static final List getSequencedStrings(List strings, int initialSequenceNumber) {
		List sequencedStrings = new ArrayList();
		int size = strings.size();
		int length = new Integer(size).toString().length();
		String prefix = StringUtils.repeat("0", length);
		for (String string : strings) {
			String sequence = StringUtils.right(prefix + (initialSequenceNumber++), length);
			String sequencedString = sequence + "-" + string;
			sequencedStrings.add(sequencedString);
		}
		return sequencedStrings;
	}

	/**
	 * Prefix the strings passed in with their position in the list (left padded with zero's). The padding is the number of digits in the size of the list. A list with 100 elements
	 * will return strings prefixed with 000, 001, etc.
	 */
	public static final List getSequencedStrings(List strings) {
		return getSequencedStrings(strings, 0);
	}

	/**
	 * Return a new List containing the unique set of strings from strings
	 */
	public static final List getUniqueStrings(List strings) {
		LinkedHashSet unique = new LinkedHashSet(strings);
		return new ArrayList(unique);
	}

	public static final List getUniqueFiles(List files) {
		LinkedHashSet unique = new LinkedHashSet(files);
		return new ArrayList(unique);
	}

	public static final List getLines(String s) {
		if (s == null) {
			return Collections. emptyList();
		}
		try {
			return IOUtils.readLines(new StringReader(s));
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}

	/**
	 * Return a new list containing the unique set of strings contained in both lists
	 */
	public static final List combineStringsUniquely(List list1, List list2) {
		List newList = getUniqueStrings(list1);
		for (String element : list2) {
			if (!newList.contains(element)) {
				newList.add(element);
			}
		}
		return newList;
	}

	protected static final  T getNewInstance(Class c) {
		try {
			return c.newInstance();
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException(e);
		} catch (InstantiationException e) {
			throw new IllegalArgumentException(e);
		}
	}

	/**
	 * Create a new list containing new instances of c
	 */
	public static final  List getNewList(Class c, int size) {
		List list = new ArrayList();
		for (int i = 0; i < size; i++) {
			T element = getNewInstance(c);
			list.add(element);
		}
		return list;
	}

	/**
	 * Return a list containing only the elements where the corresponding index in the includes list is true. includes and list
	 * must be the same size.
	 */
	public static final  List getList(List includes, List list) {
		Assert.isTrue(includes.size() == list.size());
		List included = new ArrayList();
		for (int i = 0; i < includes.size(); i++) {
			if (includes.get(i)) {
				included.add(list.get(i));
			}
		}
		return included;
	}

	/**
	 * Combine the list of lists into a single list
	 */
	public static final  List combineLists(List> listOfLists) {
		List combined = new ArrayList();
		for (List list : listOfLists) {
			combined.addAll(list);
		}
		return combined;
	}

	/**
	 * Combine the list of maps into a single map
	 */
	public static final  Map combineMaps(List> listOfMaps) {
		Map combined = new HashMap();
		for (Map map : listOfMaps) {
			combined.putAll(map);
		}
		return combined;
	}

	/**
	 * Return a combined list where required is always the first element in the list
	 */
	public static final  List combine(T element, List list) {
		Assert.notNull(element, "element is required");
		if (list == null) {
			return Collections.singletonList(element);
		} else {
			List combined = new ArrayList();
			// Always insert required as the first element in the list
			combined.add(element);
			// Add the other elements
			for (T optional : list) {
				combined.add(optional);
			}
			return combined;
		}
	}

	/**
	 * If map==null return emptyMap(), otherwise return map
	 */
	public static final  Map toEmptyMap(Map map) {
		if (map == null) {
			return Collections.emptyMap();
		} else {
			return map;
		}
	}

	/**
	 * If map==null return new HashMap(), otherwise return map
	 */
	public static final  Map toModifiableEmptyMap(Map map) {
		if (map == null) {
			return new HashMap();
		} else {
			return map;
		}
	}

	/**
	 * If key==null OR value==null return new HashMap() otherwise return
	 * new HashMap(Collections.singletonMap(key, value))
	 */
	public static final  Map toModifiableEmptyMap(K key, V value) {
		if (key == null || value == null) {
			return new HashMap();
		} else {
			return new HashMap(Collections.singletonMap(key, value));
		}
	}

	/**
	 * If key==null OR value==null return an empty map otherwise return a singleton map.
	 */
	public static final  Map toEmptyMap(K key, V value) {
		if (key == null || value == null) {
			return Collections.emptyMap();
		} else {
			return Collections.singletonMap(key, value);
		}
	}

	/**
	 * If o==null return Collections.<T> emptyList() otherwise return Collections.singletonList(o)
	 */
	public static final  List toEmptyList(T o) {
		if (o == null) {
			return Collections. emptyList();
		} else {
			return Collections.singletonList(o);
		}
	}

	/**
	 * Returns an immutable list containing only the specified object. The returned list is serializable.
	 * 
	 * @throws IllegalArgumentException
	 *             if object is null
	 */
	public static final  List singletonList(T o) {
		if (o != null) {
			return Collections.singletonList(o);
		} else {
			throw new IllegalArgumentException("nulls not allowed");
		}
	}

	/**
	 * Add keys and values to map. Keys and values must be the same size (or both null). Map cannot be null.
	 */
	public static final  void combine(Map map, List keys, List values) {
		keys = toEmptyList(keys);
		values = toEmptyList(values);
		Assert.isTrue(keys.size() == values.size(), "sizes must match");
		Assert.notNull(map, "map is null");
		for (int i = 0; i < keys.size(); i++) {
			K key = keys.get(i);
			V value = values.get(i);
			map.put(key, value);
		}
	}

	/**
	 * If list==null return an empty list otherwise return list
	 */
	public static final  List toEmptyList(List list) {
		if (list == null) {
			return Collections.emptyList();
		} else {
			return list;
		}
	}

	public static final  List toNullIfEmpty(List list) {
		if (isEmpty(list)) {
			return null;
		} else {
			return list;
		}
	}

	public static final  Collection toNullIfEmpty(Collection c) {
		if (isEmpty(c)) {
			return null;
		} else {
			return c;
		}
	}

	public static final  List getPreFilledList(int size, T value) {
		if (value == null || size < 1) {
			return Collections. emptyList();
		} else {
			List list = new ArrayList(size);
			for (int i = 0; i < size; i++) {
				list.add(value);
			}
			return list;
		}
	}

	public static final String getSpaceSeparatedCSV(List strings) {
		return getStringWithSeparator(strings, ", ");
	}

	public static final String getStringWithSeparator(List list, String separator) {
		list = toEmptyList(list);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < toEmptyList(list).size(); i++) {
			if (i != 0) {
				sb.append(separator);
			}
			Object element = list.get(i);
			if (element != null) {
				sb.append(element.toString());
			} else {
				sb.append(NullUtils.NULL);
			}
		}
		return sb.toString();
	}

	public static final String toCSV(List integers) {
		Assert.noNulls(integers);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < integers.size(); i++) {
			if (i != 0) {
				sb.append(",");
			}
			sb.append(integers.get(i));
		}
		return sb.toString();
	}

	public static final String asCSV(List strings) {
		return getCSV(strings);
	}

	public static final String getCSV(List strings) {
		return getStringWithSeparator(strings, ",");
	}

	public static final String getSpaceSeparatedString(List list) {
		return getStringWithSeparator(list, " ");
	}

	public static final Object[] toObjectArray(List objects) {
		return objects.toArray(new Object[objects.size()]);
	}

	public static final String[] toStringArray(List strings) {
		return strings.toArray(new String[strings.size()]);
	}

	public static final boolean isEmpty(Collection c) {
		return c == null || c.size() == 0;
	}

	public static final boolean isEmpty(Map m) {
		return m == null || m.size() == 0;
	}

	public static final List sortedMerge(List list, String csv) {
		Set set = new TreeSet();
		set.addAll(toEmptyList(list));
		set.addAll(getTrimmedListFromCSV(csv));
		return new ArrayList(set);
	}

	public static final List getTrimmedListFromCSV(String csv) {
		if (StringUtils.isBlank(csv)) {
			return Collections. emptyList();
		}
		String[] tokens = Str.splitAndTrimCSV(csv);
		List list = new ArrayList();
		list.addAll(Arrays.asList(tokens));
		return list;
	}

	public static final  List nullSafeCombine(List list1, List list2) {
		List combined = new ArrayList();
		if (!isEmpty(list1)) {
			combined.addAll(list1);
		}
		if (!isEmpty(list2)) {
			combined.addAll(list2);
		}
		return combined;
	}

	public static final List combineStrings(List list1, List list2, List list3) {
		List combined = new ArrayList();
		nullSafeAdd(combined, list1);
		nullSafeAdd(combined, list2);
		nullSafeAdd(combined, list3);
		return combined;
	}

	/**
	 * Return a new list containing all of the strings from both lists with string added in between the strings from both lists
	 */
	public static final List combineStrings(List list1, String string, List list2) {
		return combineStrings(list1, toEmptyList(string), list2);
	}

	/**
	 * Return a new list containing all of the strings from both lists
	 */
	public static final List combineStrings(List list1, List list2) {
		return combineStrings(list1, (String) null, list2);
	}

	/**
	 * Return a new list containing all of the strings from both lists
	 */
	@SafeVarargs
	public static final List combineStrings(List... lists) {
		List combined = new ArrayList();
		for (List list : lists) {
			combined.addAll(ImmutableList.copyOf(list));
		}
		return combined;
	}

	/**
	 * Return a new list containing all of the elements from the lists passed in
	 */
	public static final  List combine(List list1, List list2) {
		return combine(list1, list2, null);
	}

	public static final  List combine(List list1, List list2, List list3) {
		List combined = new ArrayList();
		combined.addAll(toEmptyList(list1));
		combined.addAll(toEmptyList(list2));
		combined.addAll(toEmptyList(list3));
		return combined;
	}

	public static final  void nullSafeAdd(List list1, List list2) {
		if (list2 != null) {
			list1.addAll(list2);
		}
	}

	/**
	 * Return true if s contains any of the strings from strings
	 */
	public static final boolean containsAny(String s, List strings) {
		for (String string : strings) {
			if (StringUtils.contains(s, string)) {
				return true;
			}
		}
		return false;
	}
}