View Javadoc

1   /*
2    * Copyright (C) 2004-2006 Christian Siefkes <christian@siefkes.net>.
3    * Development of this software is supported by the German Research Society,
4    * Berlin-Brandenburg Graduate School in Distributed Information Systems
5    * (DFG grant no. GRK 316).
6    *
7    * This program is free software; you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program; if not, visit
19   * http://www.gnu.org/licenses/gpl.html or write to the Free Software
20   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21   */
22  package de.fu_berlin.ties.util;
23  
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Collection;
27  import java.util.HashSet;
28  import java.util.Iterator;
29  import java.util.LinkedHashSet;
30  import java.util.List;
31  import java.util.Set;
32  
33  import de.fu_berlin.ties.text.TextUtils;
34  
35  /***
36   * A static class that provides utility methods for working with
37   * {@link java.util.Collection}s and arrays. No instances of this class can be
38   * created, only the static members should be used.
39   *
40   * @author Christian Siefkes
41   * @version $Revision: 1.10 $, $Date: 2006/10/21 16:04:27 $, $Author: siefkes $
42   */
43  public final class CollUtils {
44  
45      /***
46       * Default separator used to {@linkplain #flatten(Object[]) flatten} array
47       * if no other separator is specified: {@value} (a single space).
48       */
49      public static final String SEPARATOR = " ";
50  
51      /***
52       * Convenience method that adds all members of an array to a collection.
53       *
54       * @param <T> the type of the collection
55       * @param <E> the type of the array
56       * @param coll the collection to add to
57       * @param array the array to value to add
58       */
59      public static <T, E extends T> void addAll(final Collection<T> coll,
60              final E[] array) {
61          for (int i = 0; i < array.length; i++) {
62              coll.add(array[i]);
63          }
64      }
65  
66      /***
67       * Wraps an array into a set. Duplicates will be ignored.
68       *
69       * @param <T> the type of the array
70       * @param array the array to wrap
71       * @return a set containing the contents of the set (in random order,
72       * without duplicates)
73       */
74      public static <T> Set<T> arrayAsSet(final T[] array) {
75          return new HashSet<T>(Arrays.asList(array));
76      }
77  
78      /***
79       * Converts an object array into a boolean array, calling
80       * {@link Util#asBoolean(Object)} on each element.
81       *
82       * @param objArray the array of objects to convert
83       * @return the converted boolean array
84       * @throws IllegalArgumentException if an object's <code>toString()</code>
85       * output cannot be parsed as a boolean
86       */
87      public static boolean[] asBooleanArray(final Object[] objArray)
88      throws IllegalArgumentException {
89          final boolean[] result = new boolean[objArray.length];
90          for (int i = 0; i < objArray.length; i++) {
91              result[i] = Util.asBoolean(objArray[i]);
92          }
93          return result;
94      }
95  
96      /***
97       * Converts a string into a boolean array, calling
98       * {@link Util#asBoolean(char)} on each character.
99       *
100      * @param input the input string to convert
101      * @return the converted boolean array
102      * @throws IllegalArgumentException if one of the characters does not
103      * contain a parsable boolean
104      */
105     public static boolean[] asBooleanArray(final String input)
106     throws IllegalArgumentException {
107         final char[] chars = input.toCharArray();
108         final boolean[] result = new boolean[chars.length];
109         for (int i = 0; i < chars.length; i++) {
110             result[i] = Util.asBoolean(chars[i]);
111         }
112         return result;
113     }
114 
115     /***
116      * Converts an object array into a char array, calling
117      * {@link Util#asChar(Object)} on each element.
118      *
119      * @param objArray the array of objects to convert
120      * @return the converted char array
121      * @throws IndexOutOfBoundsException if the object's <code>toString()</code>
122      * output is the empty string (after trimming outer whitespace)
123      */
124     public static char[] asCharArray(final Object[] objArray)
125     throws IndexOutOfBoundsException {
126         final char[] result = new char[objArray.length];
127         for (int i = 0; i < objArray.length; i++) {
128             result[i] = Util.asChar(objArray[i]);
129         }
130         return result;
131     }
132 
133     /***
134      * Converts a string array into a char array. This is just a convenience
135      * wrapper for {@link String#toCharArray()}.
136      *
137      * @param input the input string to convert
138      * @return the converted char array
139      */
140     public static char[] asCharArray(final String input) {
141         return input.toCharArray();
142     }
143 
144     /***
145      * Converts an object array into a double array, calling
146      * {@link Util#asDouble(Object)} on each element.
147      *
148      * @param objArray the array of objects to convert
149      * @return the converted double array
150      * @throws NumberFormatException if an object's <code>toString()</code>
151      * output does not contain a parsable double
152      */
153     public static double[] asDoubleArray(final Object[] objArray)
154     throws NumberFormatException {
155         final double[] result = new double[objArray.length];
156         for (int i = 0; i < objArray.length; i++) {
157             result[i] = Util.asDouble(objArray[i]);
158         }
159         return result;
160     }
161 
162     /***
163      * Converts a string into a double array, by {@linkplain
164      * TextUtils#splitString(CharSequence) splitting on whitespace} and calling
165      * {@link CollUtils#asDoubleArray(Object[])} on the result.
166      *
167      * @param input the input string to convert
168      * @return the converted double array
169      * @throws NumberFormatException if one of the tokens does not contain a
170      * parsable double
171      */
172     public static double[] asDoubleArray(final String input)
173     throws NumberFormatException {
174         return asDoubleArray(TextUtils.splitString(input));
175     }
176 
177     /***
178      * Converts an object array into a float array, calling
179      * {@link Util#asFloat(Object)} on each element.
180      *
181      * @param objArray the array of objects to convert
182      * @return the converted float array
183      * @throws NumberFormatException if an object's <code>toString()</code>
184      * output does not contain a parsable float
185      */
186     public static float[] asFloatArray(final Object[] objArray)
187     throws NumberFormatException {
188         final float[] result = new float[objArray.length];
189         for (int i = 0; i < objArray.length; i++) {
190             result[i] = Util.asFloat(objArray[i]);
191         }
192         return result;
193     }
194 
195     /***
196      * Converts a string into a float array, by {@linkplain
197      * TextUtils#splitString(CharSequence) splitting on whitespace} and calling
198      * {@link CollUtils#asFloatArray(Object[])} on the result.
199      *
200      * @param input the input string to convert
201      * @return the converted float array
202      * @throws NumberFormatException if one of the tokens does not contain a
203      * parsable float
204      */
205     public static float[] asFloatArray(final String input)
206     throws NumberFormatException {
207         return asFloatArray(TextUtils.splitString(input));
208     }
209 
210     /***
211      * Converts an object array into an integer array, calling
212      * {@link Util#asInt(Object)} on each element.
213      *
214      * @param objArray the array of objects to convert
215      * @return the converted int array
216      * @throws NumberFormatException if an object's <code>toString()</code>
217      * output does not contain a parsable int
218      */
219     public static int[] asIntArray(final Object[] objArray)
220     throws NumberFormatException {
221         final int[] result = new int[objArray.length];
222         for (int i = 0; i < objArray.length; i++) {
223             result[i] = Util.asInt(objArray[i]);
224         }
225         return result;
226     }
227 
228     /***
229      * Converts a string into an integer array, by {@linkplain
230      * TextUtils#splitString(CharSequence) splitting on whitespace} and calling
231      * {@link CollUtils#asIntArray(Object[])} on the result.
232      *
233      * @param input the input string to convert
234      * @return the converted integer array
235      * @throws NumberFormatException if one of the tokens does not contain a
236      * parsable integer
237      */
238     public static int[] asIntArray(final String input)
239     throws NumberFormatException {
240         return asIntArray(TextUtils.splitString(input));
241     }
242 
243     /***
244      * Converts an object array into a long array, calling
245      * {@link Util#asLong(Object)} on each element.
246      *
247      * @param objArray the array of objects to convert
248      * @return the converted long array
249      * @throws NumberFormatException if an object's <code>toString()</code>
250      * output does not contain a parsable long
251      */
252     public static long[] asLongArray(final Object[] objArray)
253     throws NumberFormatException {
254         final long[] result = new long[objArray.length];
255         for (int i = 0; i < objArray.length; i++) {
256             result[i] = Util.asLong(objArray[i]);
257         }
258         return result;
259     }
260 
261     /***
262      * Converts a string into a long array, by {@linkplain
263      * TextUtils#splitString(CharSequence) splitting on whitespace} and calling
264      * {@link CollUtils#asLongArray(Object[])} on the result.
265      *
266      * @param input the input string to convert
267      * @return the converted long array
268      * @throws NumberFormatException if one of the tokens does not contain a
269      * parsable long
270      */
271     public static long[] asLongArray(final String input)
272     throws NumberFormatException {
273         return asLongArray(TextUtils.splitString(input));
274     }
275 
276     /***
277      * Converts an object array into a short array, calling
278      * {@link Util#asShort(Object)} on each element.
279      *
280      * @param objArray the array of objects to convert
281      * @return the converted short array
282      * @throws NumberFormatException if an object's <code>toString()</code>
283      * output does not contain a parsable short
284      */
285     public static short[] asShortArray(final Object[] objArray)
286     throws NumberFormatException {
287         final short[] result = new short[objArray.length];
288         for (int i = 0; i < objArray.length; i++) {
289             result[i] = Util.asShort(objArray[i]);
290         }
291         return result;
292     }
293 
294     /***
295      * Converts a string into a short array, by {@linkplain
296      * TextUtils#splitString(CharSequence) splitting on whitespace} and calling
297      * {@link CollUtils#asShortArray(Object[])} on the result.
298      *
299      * @param input the input string to convert
300      * @return the converted short array
301      * @throws NumberFormatException if one of the tokens does not contain a
302      * parsable short
303      */
304     public static short[] asShortArray(final String input)
305     throws NumberFormatException {
306         return asShortArray(TextUtils.splitString(input));
307     }
308 
309     /***
310      * Converts an object array into a String array, calling
311      * {@link Util#asString(Object)} on each element.
312      *
313      * @param objArray the array of objects to convert
314      * @return the converted String array
315      */
316     public static String[] asStringArray(final Object[] objArray) {
317         final String[] result = new String[objArray.length];
318         for (int i = 0; i < objArray.length; i++) {
319             result[i] = Util.asString(objArray[i]);
320         }
321         return result;
322     }
323 
324     /***
325      * Converts a string into an array of whitespace-separated tokens. This is
326      * just a convenience wrapper for
327      * {@link TextUtils#splitString(CharSequence)}.
328      *
329      * @param input the input string to convert
330      * @return the converted token array
331      */
332     public static String[] asStringArray(final String input) {
333         return TextUtils.splitString(input);
334     }
335 
336     /***
337      * Converts a string into an set of whitespace-separated tokens. This
338      * implementation converts the array returned by
339      * {@link #asShortArray(String)}} into a {@link LinkedHashSet}, so the
340      * original iteration order is preserved (but duplicates will be discarded).
341      *
342      * @param input the input string to convert
343      * @return the converted set of tokens, in original order
344      */
345     public static Set<String> asStringSet(final String input) {
346         final Set<String> result = new LinkedHashSet<String>();
347         final String[] tokens = asStringArray(input);
348 
349         for (int i = 0; i < tokens.length; i++) {
350             result.add(tokens[i]);
351         }
352         return result;
353     }
354 
355     /***
356      * Converts a raw set into a set of strings, calling the
357      * {@link Object#toString()} method for each non-<code>null</code> object.
358      *
359      * @param rawSet the set of objects to convert
360      * @return the converted set of strings, in original order
361      */
362     public static Set<String> asStringSet(final Set rawSet) {
363         final Set<String> result = new LinkedHashSet<String>();
364         final Iterator rawIter = rawSet.iterator();
365         Object obj;
366         String str;
367 
368         while (rawIter.hasNext()) {
369             obj = rawIter.next();
370             str = (obj == null) ? null : obj.toString();
371             result.add(str);
372         }
373         return result;
374     }
375 
376     /***
377      * Combines two array into a target array, inserting all elements of the
378      * first array and then all elements of the second array in the target
379      * array.
380      *
381      * @param array1 the first array to copy
382      * @param array2 the second array to copy
383      * @param targetArray the array to copy the two other array into; the
384      * type of this array must be suitable to accept elements from both array;
385      * the length of this array must be equal or greater than
386      * <code>array1.length + array2.length</code>
387      */
388     public static void combineArrays(final Object[] array1,
389                                     final Object[] array2,
390                                     final Object[] targetArray) {
391         final int lengthOfFirst = array1.length;
392         int i;
393         // copy first array into target array
394         for (i = 0; i < lengthOfFirst; i++) {
395             targetArray[i] = array1[i];
396         }
397 
398         // copy second array into target array
399         for (i = 0; i < array2.length; i++) {
400             targetArray[i + lengthOfFirst] = array2[i];
401         }
402     }
403 
404     /***
405      * Flattens the elements of the provided array into a single string
406      * of {@link Util#TRUE_CHAR} and {@link Util#FALSE_CHAR} characters,
407      * without using separator characters.
408      *
409      * @param array the array of values to join
410      * @return the flattened string
411      */
412     public static String flatten(final boolean[] array) {
413         final StringBuilder result = new StringBuilder();
414 
415         for (int i = 0; i < array.length; i++) {
416             result.append(Util.toChar(array[i]));
417         }
418 
419         return result.toString();
420     }
421 
422     /***
423      * Flattens the elements of the provided array into a single string,
424      * without using separator characters.
425      *
426      * @param array the array of values to join
427      * @return the flattened string
428      */
429     public static String flatten(final char[] array) {
430         final StringBuilder result = new StringBuilder();
431 
432         for (int i = 0; i < array.length; i++) {
433             result.append(array[i]);
434         }
435 
436         return result.toString();
437     }
438 
439     /***
440      * Flattens the elements of the provided array into a single string,
441      * separating elements by a space character.
442      *
443      * @param array the array of values to join
444      * @return the flattened string
445      */
446     public static String flatten(final double[] array) {
447         final StringBuilder result = new StringBuilder();
448 
449         for (int i = 0; i < array.length; i++) {
450             if (i > 0) {
451                 result.append(SEPARATOR);
452             }
453             result.append(array[i]);
454         }
455 
456         return result.toString();
457     }
458 
459     /***
460      * Flattens the elements of the provided array into a single string,
461      * separating elements by a space character.
462      *
463      * @param array the array of values to join
464      * @return the flattened string
465      */
466     public static String flatten(final float[] array) {
467         final StringBuilder result = new StringBuilder();
468 
469         for (int i = 0; i < array.length; i++) {
470             if (i > 0) {
471                 result.append(SEPARATOR);
472             }
473             result.append(array[i]);
474         }
475 
476         return result.toString();
477     }
478 
479     /***
480      * Flattens the elements of the provided array into a single string,
481      * separating elements by a space character.
482      *
483      * @param array the array of values to join
484      * @return the flattened string
485      */
486     public static String flatten(final int[] array) {
487         final StringBuilder result = new StringBuilder();
488 
489         for (int i = 0; i < array.length; i++) {
490             if (i > 0) {
491                 result.append(SEPARATOR);
492             }
493             result.append(array[i]);
494         }
495 
496         return result.toString();
497     }
498 
499     /***
500      * Flattens the elements of the provided array into a single string,
501      * separating elements by a space character.
502      *
503      * @param array the array of values to join
504      * @return the flattened string
505      */
506     public static String flatten(final long[] array) {
507         final StringBuilder result = new StringBuilder();
508 
509         for (int i = 0; i < array.length; i++) {
510             if (i > 0) {
511                 result.append(SEPARATOR);
512             }
513             result.append(array[i]);
514         }
515 
516         return result.toString();
517     }
518 
519     /***
520      * Flattens the objects returned by an iterator into a single string,
521      * separating elements by a space character.
522      *
523      * @param iterator the iterator over the elements to join
524      * @return the flattened string
525      */
526     public static String flatten(final Iterator iterator) {
527         return flatten(iterator, SEPARATOR);
528     }
529 
530     /***
531      * Flattens the objects returned by an iterator into a single string,
532      * separating elements by the provided separator.
533      *
534      * @param iterator the iterator over the elements to join
535      * @param separator the separator string to use
536      * @return the flattened string
537      */
538     public static String flatten(final Iterator iterator,
539             final String separator) {
540         final StringBuilder result = new StringBuilder();
541 
542         while (iterator.hasNext()) {
543             result.append(iterator.next().toString());
544             if (iterator.hasNext()) {
545                 result.append(separator);
546             }
547         }
548         return result.toString();
549     }
550 
551     /***
552      * Flattens the elements of the provided array into a single string,
553      * separating elements by a space character.
554      *
555      * @param array the array of values to join
556      * @return the flattened string
557      */
558     public static String flatten(final Object[] array) {
559         return flatten(array, SEPARATOR);
560     }
561 
562     /***
563      * Flattens the elements of the provided array into a single string,
564      * separating elements by the provided separator.
565      *
566      * @param array the array of values to join
567      * @param separator the separator string to use
568      * @return the flattened string
569      */
570     public static String flatten(final Object[] array, final String separator) {
571         final StringBuilder result = new StringBuilder();
572 
573         for (int i = 0; i < array.length; i++) {
574             if (i > 0) {
575                 result.append(separator);
576             }
577             result.append(array[i]);
578         }
579         return result.toString();
580     }
581 
582     /***
583      * Flattens the elements of the provided array into a single string,
584      * separating elements by a space character.
585      *
586      * @param array the array of values to join
587      * @return the flattened string
588      */
589     public static String flatten(final short[] array) {
590         final StringBuilder result = new StringBuilder();
591 
592         for (int i = 0; i < array.length; i++) {
593             if (i > 0) {
594                 result.append(SEPARATOR);
595             }
596             result.append(array[i]);
597         }
598 
599         return result.toString();
600     }
601 
602     /***
603      * Copied the last <em>n</em> elements from a list into a new list (or all
604      * elements, if the size of the input list is smaller or equal to
605      * <em>n</em>). Modifications of the returned list will not affect the
606      * original list and vice versa.
607      *
608      * <p>If <code>number</code> is 0 or negative or if the original list is
609      * <code>null</code> or empty, an empty list is returned.
610      *
611      * <p>Note that this is somewhat inefficient if the input list is a
612      * {@link java.util.LinkedList} because repeated calls to
613      * {@link List#get(int)} are necessary (unless the whole list is copied).
614      *
615      * @param <T> the type of the list
616      * @param list the input list
617      * @param number the number of elements to copy
618      * @return an ArrayList containing the last elements from the original list;
619      * or an empty ArrayList iff the <code>list</code> is <code>null</code>
620      */
621     public static <T> ArrayList<T> lastN(final List<? extends T> list,
622             final int number) {
623         final ArrayList<T> result;
624         if (list != null) {
625             final int size = list.size();
626             if (number <= size) {
627                 // copy the whole collection
628                 result = new ArrayList<T>(list);
629             } else {
630                 // add last N elements
631                 result = new ArrayList<T>(number);
632                 for (int i = number; i > 0; i--) {
633                     result.add(list.get(size - number));
634                 }
635             }
636         } else {
637             // return empty list if input list is null
638             result = new ArrayList<T>(0);
639         }
640         return result;
641     }
642 
643     /***
644      * Removes an object from a collection (if it is present), using
645      * identity-based comparisons instead of the
646      * {@link Object#equals(Object) equals}-based comparisons used by
647      * {@link Collection#remove(Object)}.
648      *
649      * @param <T> the type of the collection
650      * @param coll the collection to use
651      * @param obj the object to remove
652      * @return <code>true</code> if the object has been removed from the
653      * collection
654      */
655     public static <T> boolean removeByIdentity(final Collection<T> coll,
656             final T obj) {
657         final Iterator<T> iter = coll.iterator();
658 
659         // iterate all members of the collection until obj has been found
660         while (iter.hasNext()) {
661             // identity-based comparison
662             if (iter.next() == obj) {
663                 // found it
664                 iter.remove();
665                 return true;
666             }
667         }
668 
669         // not found
670         return false;
671     }
672 
673 
674     /***
675      * Private constructor prevents creation of instances.
676      */
677     private CollUtils() {
678         super();
679     }
680 
681 }