001    /*--------------------------------------------------------------------------+
002    $Id: CollectionUtils.java 27324 2010-03-31 08:53:26Z hummelb $
003    |                                                                          |
004    | Copyright 2005-2010 Technische Universitaet Muenchen                     |
005    |                                                                          |
006    | Licensed under the Apache License, Version 2.0 (the "License");          |
007    | you may not use this file except in compliance with the License.         |
008    | You may obtain a copy of the License at                                  |
009    |                                                                          |
010    |    http://www.apache.org/licenses/LICENSE-2.0                            |
011    |                                                                          |
012    | Unless required by applicable law or agreed to in writing, software      |
013    | distributed under the License is distributed on an "AS IS" BASIS,        |
014    | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015    | See the License for the specific language governing permissions and      |
016    | limitations under the License.                                           |
017    +--------------------------------------------------------------------------*/
018    package edu.tum.cs.commons.collections;
019    
020    import java.util.ArrayList;
021    import java.util.Arrays;
022    import java.util.Collection;
023    import java.util.Collections;
024    import java.util.Comparator;
025    import java.util.Deque;
026    import java.util.HashSet;
027    import java.util.Iterator;
028    import java.util.List;
029    import java.util.Map;
030    import java.util.Set;
031    import java.util.SortedMap;
032    import java.util.SortedSet;
033    
034    /**
035     * This class offers utility methods for collections. In can be seen as an
036     * extension to {@link Collections}.
037     * 
038     * @author Florian Deissenboeck
039     * @author $Author: hummelb $
040     * 
041     * @version $Revision: 27324 $
042     * @levd.rating GREEN Hash: 18A8495D2E7BB7DE351987B60C0E3338
043     */
044    public class CollectionUtils {
045            /** Empty unmodifiable list. */
046            @SuppressWarnings("unchecked")
047            private static final UnmodifiableList<?> EMPTY_LIST = new UnmodifiableList<Object>(
048                            Collections.EMPTY_LIST);
049    
050            /** Empty unmodifiable map. */
051            @SuppressWarnings("unchecked")
052            private static final UnmodifiableMap<?, ?> EMPTY_MAP = new UnmodifiableMap<Object, Object>(
053                            Collections.EMPTY_MAP);
054    
055            /** Empty unmodifiable set. */
056            @SuppressWarnings("unchecked")
057            private static final UnmodifiableSet<?> EMPTY_SET = new UnmodifiableSet<Object>(
058                            Collections.EMPTY_SET);
059    
060            /**
061             * Create an hashed set from an array.
062             * 
063             * @param <T>
064             *            type
065             * @param elements
066             *            elements in the set.
067             * @return the set.
068             * @see Arrays#asList(Object[])
069             */
070            public static <T> HashSet<T> asHashSet(T... elements) {
071                    HashSet<T> result = new HashSet<T>();
072    
073                    Collections.addAll(result, elements);
074    
075                    return result;
076            }
077    
078            /**
079             * Returns a new unmodifiable collection wrapping the given collection. This
080             * method is here to avoid retyping the generic argument for the collection
081             * class.
082             */
083            public static <T> UnmodifiableCollection<T> asUnmodifiable(Collection<T> c) {
084                    return new UnmodifiableCollection<T>(c);
085            }
086    
087            /**
088             * Returns a new unmodifiable hashed list map wrapping the given map. This
089             * method is here to avoid retyping the generic arguments for the sorted map
090             * class.
091             */
092            public static <S, T> UnmodifiableHashedListMap<S, T> asUnmodifiable(
093                            HashedListMap<S, T> m) {
094                    return new UnmodifiableHashedListMap<S, T>(m);
095            }
096    
097            /**
098             * Returns a new unmodifiable list wrapping the given list. This method is
099             * here to avoid retyping the generic argument for the list class.
100             */
101            public static <T> UnmodifiableList<T> asUnmodifiable(List<T> l) {
102                    return new UnmodifiableList<T>(l);
103            }
104    
105            /**
106             * Returns a new unmodifiable map wrapping the given map. This method is
107             * here to avoid retyping the generic arguments for the map class.
108             */
109            public static <S, T> UnmodifiableMap<S, T> asUnmodifiable(Map<S, T> m) {
110                    return new UnmodifiableMap<S, T>(m);
111            }
112    
113            /**
114             * Returns a new unmodifiable set wrapping the given set. This method is
115             * here to avoid retyping the generic argument for the set class.
116             */
117            public static <T> UnmodifiableSet<T> asUnmodifiable(Set<T> s) {
118                    return new UnmodifiableSet<T>(s);
119            }
120    
121            /**
122             * Returns a new unmodifiable sorted map wrapping the given sorted map. This
123             * method is here to avoid retyping the generic arguments for the sorted map
124             * class.
125             */
126            public static <S, T> UnmodifiableSortedMap<S, T> asUnmodifiable(
127                            SortedMap<S, T> m) {
128                    return new UnmodifiableSortedMap<S, T>(m);
129            }
130    
131            /**
132             * Returns a new unmodifiable sorted set wrapping the given sorted set. This
133             * method is here to avoid retyping the generic argument for the sorted set
134             * class.
135             */
136            public static <T> UnmodifiableSortedSet<T> asUnmodifiable(SortedSet<T> s) {
137                    return new UnmodifiableSortedSet<T>(s);
138            }
139    
140            /**
141             * The way this method is defined allows to assign it to all parameterized
142             * types, i.e. bot of the following statements are accepted by the compiler
143             * without warnings:
144             * 
145             * <pre>
146             * UnmodifiableList&lt;String&gt; emptyList = CollectionUtils.emptyList();
147             * 
148             * UnmodifiableList&lt;Date&gt; emptyList = CollectionUtils.emptyList();
149             * </pre>
150             * 
151             * @param <T>
152             * @return the emtpy list
153             */
154            @SuppressWarnings("unchecked")
155            public static final <T> UnmodifiableList<T> emptyList() {
156                    return (UnmodifiableList<T>) EMPTY_LIST;
157            }
158    
159            /** Returns an empty map. See {@link #emptyList()} for further details. */
160            @SuppressWarnings("unchecked")
161            public static final <S, T> UnmodifiableMap<S, T> emptyMap() {
162                    return (UnmodifiableMap<S, T>) EMPTY_MAP;
163            }
164    
165            /** Returns an empty set. See {@link #emptyList()} for further details. */
166            @SuppressWarnings("unchecked")
167            public static final <T> UnmodifiableSet<T> emptySet() {
168                    return (UnmodifiableSet<T>) EMPTY_SET;
169            }
170    
171            /**
172             * Sorts the specified list into ascending order, according to the
173             * <i>natural ordering</i> of its elements.
174             * <p>
175             * All elements in the list must implement the Comparable interface.
176             * Furthermore, all elements in the list must be mutually comparable (that
177             * is, e1.compareTo(e2) must not throw a <code>ClassCastException</code> for
178             * any elements e1 and e2 in the list).
179             * <p>
180             * This method does not modify the original collection.
181             */
182            public static <T extends Comparable<? super T>> List<T> sort(
183                            Collection<T> collection) {
184                    ArrayList<T> list = new ArrayList<T>(collection);
185                    Collections.sort(list);
186                    return list;
187            }
188    
189            /**
190             * Returns a list that contains the elements of the specified list in
191             * reversed order.
192             * <p>
193             * This method does not modify the original collection.
194             */
195            public static <T> List<T> reverse(Collection<T> list) {
196                    ArrayList<T> reversed = new ArrayList<T>(list);
197                    Collections.reverse(reversed);
198                    return reversed;
199            }
200    
201            /**
202             * Sorts the specified list according to the order induced by the specified
203             * comparator.
204             * <p>
205             * All elements in the list must implement the Comparable interface.
206             * Furthermore, all elements in the list must be mutually comparable (that
207             * is, e1.compareTo(e2) must not throw a <code>ClassCastException</code> for
208             * any elements e1 and e2 in the list).
209             * <p>
210             * This method does not modify the original collection.
211             */
212            public static <T> List<T> sort(Collection<T> collection,
213                            Comparator<? super T> comparator) {
214                    ArrayList<T> list = new ArrayList<T>(collection);
215                    Collections.sort(list, comparator);
216                    return list;
217            }
218    
219            /** Returns a sorted unmodifiable list for a collection. */
220            public static <T extends Comparable<T>> UnmodifiableList<T> asSortedUnmodifiableList(
221                            Collection<T> collection) {
222                    return asUnmodifiable(sort(collection));
223            }
224    
225            /**
226             * Returns a sorted unmodifiable list for a collection.
227             * 
228             * @param comparator
229             *            Comparator used for sorting
230             */
231            public static <T extends Comparable<T>> UnmodifiableList<T> asSortedUnmodifiableList(
232                            Collection<T> collection, Comparator<? super T> comparator) {
233                    return asUnmodifiable(sort(collection, comparator));
234            }
235    
236            /**
237             * Returns one object from an {@link Iterable} or <code>null</code> if the
238             * iterable is empty.
239             */
240            public static <T> T getAny(Iterable<T> iterable) {
241                    Iterator<T> iterator = iterable.iterator();
242                    if (!iterator.hasNext()) {
243                            return null;
244                    }
245                    return iterator.next();
246            }
247    
248            /**
249             * Convert collection to array. This is a bit cleaner version of
250             * {@link Collection#toArray(Object[])}.
251             */
252            @SuppressWarnings("unchecked")
253            public static <T> T[] toArray(Collection<? extends T> collection,
254                            Class<T> type) {
255                    T[] result = (T[]) java.lang.reflect.Array.newInstance(type, collection
256                                    .size());
257    
258                    Iterator<? extends T> it = collection.iterator();
259                    for (int i = 0; i < collection.size(); i++) {
260                            result[i] = it.next();
261                    }
262    
263                    return result;
264            }
265    
266            /**
267             * Copy an array. This is a shortcut for
268             * {@link Arrays#copyOf(Object[], int)} that does not require to specify the
269             * length.
270             */
271            public static <T> T[] copyArray(T[] original) {
272                    return Arrays.copyOf(original, original.length);
273            }
274    
275            /**
276             * Compute list of unordered pairs for all elements contained in a
277             * collection.
278             */
279            public static <T> List<ImmutablePair<T, T>> computeUnorderedPairs(
280                            Collection<T> collection) {
281                    List<T> elements = new ArrayList<T>(collection);
282                    List<ImmutablePair<T, T>> pairs = new ArrayList<ImmutablePair<T, T>>();
283    
284                    int size = elements.size();
285                    for (int firstIndex = 0; firstIndex < size; firstIndex++) {
286                            for (int secondIndex = firstIndex + 1; secondIndex < size; secondIndex++) {
287                                    pairs.add(new ImmutablePair<T, T>(elements.get(firstIndex),
288                                                    elements.get(secondIndex)));
289                            }
290                    }
291    
292                    return pairs;
293            }
294    
295            /** Returns the last element in list or <code>null</code>, if list is empty. */
296            @SuppressWarnings("unchecked")
297            public static <T> T getLast(List<T> list) {
298                    if (list.isEmpty()) {
299                            return null;
300                    }
301                    if (list instanceof Deque<?>) {
302                            return ((Deque<T>) list).getLast();
303                    }
304                    return list.get(list.size() - 1);
305            }
306    
307    }