View Javadoc

1   /**
2    * Copyright 2010-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.common.util;
17  
18  import java.io.File;
19  import java.io.IOException;
20  import java.io.StringReader;
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  import java.util.TreeSet;
30  
31  import org.apache.commons.io.IOUtils;
32  import org.apache.commons.lang3.StringUtils;
33  
34  public class CollectionUtils {
35  
36  	/**
37  	 * Null safe method for converting an array of objects into a list. Never returns null.
38  	 */
39  	public static List<Object> asList(Object... objects) {
40  		List<Object> list = new ArrayList<Object>();
41  		if (objects == null) {
42  			return list;
43  		}
44  		for (Object element : objects) {
45  			if (element != null) {
46  				list.add(element);
47  			}
48  		}
49  		return list;
50  	}
51  
52  	/**
53  	 * Null safe method for converting an untyped array of classes into a list. Never returns null.
54  	 */
55  	public static List<Class<?>> asList(Class<?>... classes) {
56  		List<Class<?>> list = new ArrayList<Class<?>>();
57  		if (classes == null) {
58  			return list;
59  		}
60  		for (Class<?> element : classes) {
61  			if (element != null) {
62  				list.add(element);
63  			}
64  		}
65  		return list;
66  	}
67  
68  	/**
69  	 * Return an array of int's that represents as even of a split as possible
70  	 * 
71  	 * For example: passing in 100,7 returns 15, 15, 14, 14, 14, 14, 14
72  	 * 
73  	 * @param numerator
74  	 * @param denominator
75  	 * @return
76  	 */
77  	public static int[] getDivideEvenly(int number, int howManyWays) {
78  		Assert.isTrue(howManyWays > 0, "howManyWays must be a positive integer");
79  		int quotient = number / howManyWays;
80  		int remainder = number % howManyWays;
81  
82  		int[] lengths = new int[howManyWays];
83  		for (int i = 0; i < howManyWays; i++) {
84  			int length = i < remainder ? quotient + 1 : quotient;
85  			lengths[i] = length;
86  		}
87  		return lengths;
88  	}
89  
90  	/**
91  	 * Split <code>elements</code> evenly into separate lists divided up <code>howManyWays</code>
92  	 */
93  	public static final <T> List<List<T>> splitEvenly(List<T> elements, int howManyWays) {
94  		// Can't split 2 things 3 ways
95  		if (howManyWays > elements.size()) {
96  			howManyWays = elements.size();
97  		}
98  		int[] lengths = getDivideEvenly(elements.size(), howManyWays);
99  		int offset = 0;
100 		List<List<T>> listOfLists = new ArrayList<List<T>>();
101 		for (int i = 0; i < lengths.length; i++) {
102 			int length = lengths[i];
103 			List<T> sublist = new ArrayList<T>();
104 			for (int j = offset; j < offset + length; j++) {
105 				sublist.add(elements.get(j));
106 			}
107 			listOfLists.add(sublist);
108 			offset += length;
109 		}
110 		return listOfLists;
111 	}
112 
113 	/**
114 	 * 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
115 	 * will return strings prefixed with 000, 001, etc.
116 	 */
117 	public static final List<String> getSequencedStrings(List<String> strings, int initialSequenceNumber) {
118 		List<String> sequencedStrings = new ArrayList<String>();
119 		int size = strings.size();
120 		int length = new Integer(size).toString().length();
121 		String prefix = StringUtils.repeat("0", length);
122 		for (String string : strings) {
123 			String sequence = StringUtils.right(prefix + (initialSequenceNumber++), length);
124 			String sequencedString = sequence + "-" + string;
125 			sequencedStrings.add(sequencedString);
126 		}
127 		return sequencedStrings;
128 	}
129 
130 	/**
131 	 * 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
132 	 * will return strings prefixed with 000, 001, etc.
133 	 */
134 	public static final List<String> getSequencedStrings(List<String> strings) {
135 		return getSequencedStrings(strings, 0);
136 	}
137 
138 	/**
139 	 * Return a new <code>List</code> containing the unique set of strings from <code>strings</code>
140 	 */
141 	public static final List<String> getUniqueStrings(List<String> strings) {
142 		List<String> unique = new ArrayList<String>();
143 		for (String string : strings) {
144 			if (!unique.contains(string)) {
145 				unique.add(string);
146 			}
147 		}
148 		return unique;
149 	}
150 
151 	public static final List<File> getUniqueFiles(List<File> files) {
152 		List<String> strings = new ArrayList<String>();
153 		for (File file : files) {
154 			strings.add(LocationUtils.getCanonicalPath(file));
155 		}
156 		List<String> uniqueStrings = getUniqueStrings(strings);
157 		List<File> uniqueFiles = new ArrayList<File>();
158 		for (String uniqueString : uniqueStrings) {
159 			uniqueFiles.add(new File(uniqueString));
160 		}
161 		return uniqueFiles;
162 	}
163 
164 	public static final List<String> getLines(String s) {
165 		if (s == null) {
166 			return Collections.<String> emptyList();
167 		}
168 		try {
169 			return IOUtils.readLines(new StringReader(s));
170 		} catch (IOException e) {
171 			throw new IllegalStateException(e);
172 		}
173 	}
174 
175 	/**
176 	 * Return a new list containing the unique set of strings contained in both lists
177 	 */
178 	public static final List<String> combineStringsUniquely(List<String> list1, List<String> list2) {
179 		List<String> newList = getUniqueStrings(list1);
180 		for (String element : list2) {
181 			if (!newList.contains(element)) {
182 				newList.add(element);
183 			}
184 		}
185 		return newList;
186 	}
187 
188 	protected static final <T> T getNewInstance(Class<T> c) {
189 		try {
190 			return c.newInstance();
191 		} catch (IllegalAccessException e) {
192 			throw new IllegalArgumentException(e);
193 		} catch (InstantiationException e) {
194 			throw new IllegalArgumentException(e);
195 		}
196 	}
197 
198 	/**
199 	 * Create a new list containing new instances of <code>c</code>
200 	 */
201 	public static final <T> List<T> getNewList(Class<T> c, int size) {
202 		List<T> list = new ArrayList<T>();
203 		for (int i = 0; i < size; i++) {
204 			T element = getNewInstance(c);
205 			list.add(element);
206 		}
207 		return list;
208 	}
209 
210 	/**
211 	 * Return a list containing only the elements where the corresponding index in the <code>includes</code> list is <code>true</code>. <code>includes</code> and <code>list</code>
212 	 * must be the same size.
213 	 */
214 	public static final <T> List<T> getList(List<Boolean> includes, List<T> list) {
215 		Assert.isTrue(includes.size() == list.size());
216 		List<T> included = new ArrayList<T>();
217 		for (int i = 0; i < includes.size(); i++) {
218 			if (includes.get(i)) {
219 				included.add(list.get(i));
220 			}
221 		}
222 		return included;
223 	}
224 
225 	/**
226 	 * Combine the list of lists into a single list
227 	 */
228 	public static final <T> List<T> combineLists(List<List<T>> listOfLists) {
229 		List<T> combined = new ArrayList<T>();
230 		for (List<T> list : listOfLists) {
231 			combined.addAll(list);
232 		}
233 		return combined;
234 	}
235 
236 	/**
237 	 * Combine the list of maps into a single map
238 	 */
239 	public static final <K, V> Map<K, V> combineMaps(List<Map<K, V>> listOfMaps) {
240 		Map<K, V> combined = new HashMap<K, V>();
241 		for (Map<K, V> map : listOfMaps) {
242 			combined.putAll(map);
243 		}
244 		return combined;
245 	}
246 
247 	/**
248 	 * Return a combined list where <code>required</code> is always the first element in the list
249 	 */
250 	public static final <T> List<T> combine(T element, List<T> list) {
251 		Assert.notNull(element, "element is required");
252 		if (list == null) {
253 			return Collections.singletonList(element);
254 		} else {
255 			List<T> combined = new ArrayList<T>();
256 			// Always insert required as the first element in the list
257 			combined.add(element);
258 			// Add the other elements
259 			for (T optional : list) {
260 				combined.add(optional);
261 			}
262 			return combined;
263 		}
264 	}
265 
266 	/**
267 	 * If <code>o==null</code> return an empty list otherwise return a singleton list.
268 	 */
269 	public static final <T> List<T> toEmptyList(T o) {
270 		if (o == null) {
271 			return Collections.<T> emptyList();
272 		} else {
273 			return Collections.singletonList(o);
274 		}
275 	}
276 
277 	/**
278 	 * If <code>list==null</code> return an empty list otherwise return <code>list</code>
279 	 */
280 	public static final <T> List<T> toEmptyList(List<T> list) {
281 		if (list == null) {
282 			return Collections.<T> emptyList();
283 		} else {
284 			return list;
285 		}
286 	}
287 
288 	public static final <T> List<T> toNullIfEmpty(List<T> list) {
289 		if (isEmpty(list)) {
290 			return null;
291 		} else {
292 			return list;
293 		}
294 	}
295 
296 	public static final <T> Collection<T> toNullIfEmpty(Collection<T> c) {
297 		if (isEmpty(c)) {
298 			return null;
299 		} else {
300 			return c;
301 		}
302 	}
303 
304 	public static final <T> List<T> getPreFilledList(int size, T value) {
305 		if (value == null || size < 1) {
306 			return Collections.<T> emptyList();
307 		} else {
308 			List<T> list = new ArrayList<T>(size);
309 			for (int i = 0; i < size; i++) {
310 				list.add(value);
311 			}
312 			return list;
313 		}
314 	}
315 
316 	public static final String getCSV(List<String> strings) {
317 		StringBuilder sb = new StringBuilder();
318 		for (int i = 0; i < toEmptyList(strings).size(); i++) {
319 			if (i != 0) {
320 				sb.append(",");
321 			}
322 			sb.append(strings.get(i));
323 		}
324 		return sb.toString();
325 	}
326 
327 	public static final String getSpaceSeparatedString(List<?> list) {
328 		list = toEmptyList(list);
329 		StringBuilder sb = new StringBuilder();
330 		for (int i = 0; i < list.size(); i++) {
331 			if (i != 0) {
332 				sb.append(" ");
333 			}
334 			sb.append(list.get(i).toString());
335 		}
336 		return sb.toString();
337 	}
338 
339 	public static final Object[] toObjectArray(List<Object> objects) {
340 		return objects.toArray(new Object[objects.size()]);
341 	}
342 
343 	public static final String[] toStringArray(List<String> strings) {
344 		return strings.toArray(new String[strings.size()]);
345 	}
346 
347 	public static final boolean isEmpty(Collection<?> c) {
348 		return c == null || c.size() == 0;
349 	}
350 
351 	public static final List<String> sortedMerge(List<String> list, String csv) {
352 		Set<String> set = new TreeSet<String>();
353 		set.addAll(toEmptyList(list));
354 		set.addAll(getTrimmedListFromCSV(csv));
355 		return new ArrayList<String>(set);
356 	}
357 
358 	public static final List<String> getTrimmedListFromCSV(String csv) {
359 		if (StringUtils.isBlank(csv)) {
360 			return Collections.<String> emptyList();
361 		}
362 		List<String> list = new ArrayList<String>();
363 		String[] tokens = Str.splitAndTrimCSV(csv);
364 		list.addAll(Arrays.asList(tokens));
365 		return list;
366 	}
367 
368 	public static final List<String> combineStrings(List<String> list1, List<String> list2, List<String> list3) {
369 		List<String> combined = new ArrayList<String>();
370 		nullSafeAdd(combined, list1);
371 		nullSafeAdd(combined, list2);
372 		nullSafeAdd(combined, list3);
373 		return combined;
374 	}
375 
376 	/**
377 	 * Return a new list containing all of the strings from both lists with string added in between the strings from both lists
378 	 */
379 	public static final List<String> combineStrings(List<String> list1, String string, List<String> list2) {
380 		return combineStrings(list1, toEmptyList(string), list2);
381 	}
382 
383 	/**
384 	 * Return a new list containing all of the strings from both lists
385 	 */
386 	public static final List<String> combineStrings(List<String> list1, List<String> list2) {
387 		return combineStrings(list1, (String) null, list2);
388 	}
389 
390 	public static final <T> void nullSafeAdd(List<T> list1, List<T> list2) {
391 		if (list2 != null) {
392 			list1.addAll(list2);
393 		}
394 	}
395 
396 	/**
397 	 * Return <code>true</code> if <code>s</code> contains any of the strings from <code>strings</code>
398 	 */
399 	public static final boolean containsAny(String s, List<String> strings) {
400 		for (String string : strings) {
401 			if (StringUtils.contains(s, string)) {
402 				return true;
403 			}
404 		}
405 		return false;
406 	}
407 }