summaryrefslogtreecommitdiffstats
path: root/guava/src/com/google/common/collect/Collections2.java
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google/common/collect/Collections2.java')
-rw-r--r--guava/src/com/google/common/collect/Collections2.java703
1 files changed, 703 insertions, 0 deletions
diff --git a/guava/src/com/google/common/collect/Collections2.java b/guava/src/com/google/common/collect/Collections2.java
new file mode 100644
index 0000000..e3ae14a
--- /dev/null
+++ b/guava/src/com/google/common/collect/Collections2.java
@@ -0,0 +1,703 @@
+/*
+ * Copyright (C) 2008 The Guava Authors
+ *
+ * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 com.google.common.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.math.LongMath.binomial;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.math.IntMath;
+import com.google.common.primitives.Ints;
+
+import java.util.AbstractCollection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * Provides static methods for working with {@code Collection} instances.
+ *
+ * @author Chris Povirk
+ * @author Mike Bostock
+ * @author Jared Levy
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public final class Collections2 {
+ private Collections2() {}
+
+ /**
+ * Returns the elements of {@code unfiltered} that satisfy a predicate. The
+ * returned collection is a live view of {@code unfiltered}; changes to one
+ * affect the other.
+ *
+ * <p>The resulting collection's iterator does not support {@code remove()},
+ * but all other collection methods are supported. When given an element that
+ * doesn't satisfy the predicate, the collection's {@code add()} and {@code
+ * addAll()} methods throw an {@link IllegalArgumentException}. When methods
+ * such as {@code removeAll()} and {@code clear()} are called on the filtered
+ * collection, only elements that satisfy the filter will be removed from the
+ * underlying collection.
+ *
+ * <p>The returned collection isn't threadsafe or serializable, even if
+ * {@code unfiltered} is.
+ *
+ * <p>Many of the filtered collection's methods, such as {@code size()},
+ * iterate across every element in the underlying collection and determine
+ * which elements satisfy the filter. When a live view is <i>not</i> needed,
+ * it may be faster to copy {@code Iterables.filter(unfiltered, predicate)}
+ * and use the copy.
+ *
+ * <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>,
+ * as documented at {@link Predicate#apply}. Do not provide a predicate such
+ * as {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent
+ * with equals. (See {@link Iterables#filter(Iterable, Class)} for related
+ * functionality.)
+ */
+ // TODO(kevinb): how can we omit that Iterables link when building gwt
+ // javadoc?
+ public static <E> Collection<E> filter(
+ Collection<E> unfiltered, Predicate<? super E> predicate) {
+ if (unfiltered instanceof FilteredCollection) {
+ // Support clear(), removeAll(), and retainAll() when filtering a filtered
+ // collection.
+ return ((FilteredCollection<E>) unfiltered).createCombined(predicate);
+ }
+
+ return new FilteredCollection<E>(
+ checkNotNull(unfiltered), checkNotNull(predicate));
+ }
+
+ /**
+ * Delegates to {@link Collection#contains}. Returns {@code false} if the
+ * {@code contains} method throws a {@code ClassCastException}.
+ */
+ static boolean safeContains(Collection<?> collection, Object object) {
+ try {
+ return collection.contains(object);
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ static class FilteredCollection<E> implements Collection<E> {
+ final Collection<E> unfiltered;
+ final Predicate<? super E> predicate;
+
+ FilteredCollection(Collection<E> unfiltered,
+ Predicate<? super E> predicate) {
+ this.unfiltered = unfiltered;
+ this.predicate = predicate;
+ }
+
+ FilteredCollection<E> createCombined(Predicate<? super E> newPredicate) {
+ return new FilteredCollection<E>(unfiltered,
+ Predicates.<E>and(predicate, newPredicate));
+ // .<E> above needed to compile in JDK 5
+ }
+
+ @Override
+ public boolean add(E element) {
+ checkArgument(predicate.apply(element));
+ return unfiltered.add(element);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends E> collection) {
+ for (E element : collection) {
+ checkArgument(predicate.apply(element));
+ }
+ return unfiltered.addAll(collection);
+ }
+
+ @Override
+ public void clear() {
+ Iterables.removeIf(unfiltered, predicate);
+ }
+
+ @Override
+ public boolean contains(Object element) {
+ try {
+ // unsafe cast can result in a CCE from predicate.apply(), which we
+ // will catch
+ @SuppressWarnings("unchecked")
+ E e = (E) element;
+
+ /*
+ * We check whether e satisfies the predicate, when we really mean to
+ * check whether the element contained in the set does. This is ok as
+ * long as the predicate is consistent with equals, as required.
+ */
+ return predicate.apply(e) && unfiltered.contains(element);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> collection) {
+ for (Object element : collection) {
+ if (!contains(element)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return !Iterators.any(unfiltered.iterator(), predicate);
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return Iterators.filter(unfiltered.iterator(), predicate);
+ }
+
+ @Override
+ public boolean remove(Object element) {
+ try {
+ // unsafe cast can result in a CCE from predicate.apply(), which we
+ // will catch
+ @SuppressWarnings("unchecked")
+ E e = (E) element;
+
+ // See comment in contains() concerning predicate.apply(e)
+ return predicate.apply(e) && unfiltered.remove(element);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean removeAll(final Collection<?> collection) {
+ checkNotNull(collection);
+ Predicate<E> combinedPredicate = new Predicate<E>() {
+ @Override
+ public boolean apply(E input) {
+ return predicate.apply(input) && collection.contains(input);
+ }
+ };
+ return Iterables.removeIf(unfiltered, combinedPredicate);
+ }
+
+ @Override
+ public boolean retainAll(final Collection<?> collection) {
+ checkNotNull(collection);
+ Predicate<E> combinedPredicate = new Predicate<E>() {
+ @Override
+ public boolean apply(E input) {
+ // See comment in contains() concerning predicate.apply(e)
+ return predicate.apply(input) && !collection.contains(input);
+ }
+ };
+ return Iterables.removeIf(unfiltered, combinedPredicate);
+ }
+
+ @Override
+ public int size() {
+ return Iterators.size(iterator());
+ }
+
+ @Override
+ public Object[] toArray() {
+ // creating an ArrayList so filtering happens once
+ return Lists.newArrayList(iterator()).toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] array) {
+ return Lists.newArrayList(iterator()).toArray(array);
+ }
+
+ @Override public String toString() {
+ return Iterators.toString(iterator());
+ }
+ }
+
+ /**
+ * Returns a collection that applies {@code function} to each element of
+ * {@code fromCollection}. The returned collection is a live view of {@code
+ * fromCollection}; changes to one affect the other.
+ *
+ * <p>The returned collection's {@code add()} and {@code addAll()} methods
+ * throw an {@link UnsupportedOperationException}. All other collection
+ * methods are supported, as long as {@code fromCollection} supports them.
+ *
+ * <p>The returned collection isn't threadsafe or serializable, even if
+ * {@code fromCollection} is.
+ *
+ * <p>When a live view is <i>not</i> needed, it may be faster to copy the
+ * transformed collection and use the copy.
+ *
+ * <p>If the input {@code Collection} is known to be a {@code List}, consider
+ * {@link Lists#transform}. If only an {@code Iterable} is available, use
+ * {@link Iterables#transform}.
+ */
+ public static <F, T> Collection<T> transform(Collection<F> fromCollection,
+ Function<? super F, T> function) {
+ return new TransformedCollection<F, T>(fromCollection, function);
+ }
+
+ static class TransformedCollection<F, T> extends AbstractCollection<T> {
+ final Collection<F> fromCollection;
+ final Function<? super F, ? extends T> function;
+
+ TransformedCollection(Collection<F> fromCollection,
+ Function<? super F, ? extends T> function) {
+ this.fromCollection = checkNotNull(fromCollection);
+ this.function = checkNotNull(function);
+ }
+
+ @Override public void clear() {
+ fromCollection.clear();
+ }
+
+ @Override public boolean isEmpty() {
+ return fromCollection.isEmpty();
+ }
+
+ @Override public Iterator<T> iterator() {
+ return Iterators.transform(fromCollection.iterator(), function);
+ }
+
+ @Override public int size() {
+ return fromCollection.size();
+ }
+ }
+
+ /**
+ * Returns {@code true} if the collection {@code self} contains all of the
+ * elements in the collection {@code c}.
+ *
+ * <p>This method iterates over the specified collection {@code c}, checking
+ * each element returned by the iterator in turn to see if it is contained in
+ * the specified collection {@code self}. If all elements are so contained,
+ * {@code true} is returned, otherwise {@code false}.
+ *
+ * @param self a collection which might contain all elements in {@code c}
+ * @param c a collection whose elements might be contained by {@code self}
+ */
+ static boolean containsAllImpl(Collection<?> self, Collection<?> c) {
+ checkNotNull(self);
+ for (Object o : c) {
+ if (!self.contains(o)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * An implementation of {@link Collection#toString()}.
+ */
+ static String toStringImpl(final Collection<?> collection) {
+ StringBuilder sb
+ = newStringBuilderForCollection(collection.size()).append('[');
+ STANDARD_JOINER.appendTo(
+ sb, Iterables.transform(collection, new Function<Object, Object>() {
+ @Override public Object apply(Object input) {
+ return input == collection ? "(this Collection)" : input;
+ }
+ }));
+ return sb.append(']').toString();
+ }
+
+ /**
+ * Returns best-effort-sized StringBuilder based on the given collection size.
+ */
+ static StringBuilder newStringBuilderForCollection(int size) {
+ checkArgument(size >= 0, "size must be non-negative");
+ return new StringBuilder((int) Math.min(size * 8L, Ints.MAX_POWER_OF_TWO));
+ }
+
+ /**
+ * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
+ */
+ static <T> Collection<T> cast(Iterable<T> iterable) {
+ return (Collection<T>) iterable;
+ }
+
+ static final Joiner STANDARD_JOINER = Joiner.on(", ").useForNull("null");
+
+ /**
+ * Returns a {@link Collection} of all the permutations of the specified
+ * {@link Iterable}.
+ *
+ * <p><i>Notes:</i> This is an implementation of the algorithm for
+ * Lexicographical Permutations Generation, described in Knuth's "The Art of
+ * Computer Programming", Volume 4, Chapter 7, Section 7.2.1.2. The
+ * iteration order follows the lexicographical order. This means that
+ * the first permutation will be in ascending order, and the last will be in
+ * descending order.
+ *
+ * <p>Duplicate elements are considered equal. For example, the list [1, 1]
+ * will have only one permutation, instead of two. This is why the elements
+ * have to implement {@link Comparable}.
+ *
+ * <p>An empty iterable has only one permutation, which is an empty list.
+ *
+ * <p>This method is equivalent to
+ * {@code Collections2.orderedPermutations(list, Ordering.natural())}.
+ *
+ * @param elements the original iterable whose elements have to be permuted.
+ * @return an immutable {@link Collection} containing all the different
+ * permutations of the original iterable.
+ * @throws NullPointerException if the specified iterable is null or has any
+ * null elements.
+ * @since 12.0
+ */
+ @Beta public static <E extends Comparable<? super E>>
+ Collection<List<E>> orderedPermutations(Iterable<E> elements) {
+ return orderedPermutations(elements, Ordering.natural());
+ }
+
+ /**
+ * Returns a {@link Collection} of all the permutations of the specified
+ * {@link Iterable} using the specified {@link Comparator} for establishing
+ * the lexicographical ordering.
+ *
+ * <p>Examples: <pre> {@code
+ *
+ * for (List<String> perm : orderedPermutations(asList("b", "c", "a"))) {
+ * println(perm);
+ * }
+ * // -> ["a", "b", "c"]
+ * // -> ["a", "c", "b"]
+ * // -> ["b", "a", "c"]
+ * // -> ["b", "c", "a"]
+ * // -> ["c", "a", "b"]
+ * // -> ["c", "b", "a"]
+ *
+ * for (List<Integer> perm : orderedPermutations(asList(1, 2, 2, 1))) {
+ * println(perm);
+ * }
+ * // -> [1, 1, 2, 2]
+ * // -> [1, 2, 1, 2]
+ * // -> [1, 2, 2, 1]
+ * // -> [2, 1, 1, 2]
+ * // -> [2, 1, 2, 1]
+ * // -> [2, 2, 1, 1]}</pre>
+ *
+ * <p><i>Notes:</i> This is an implementation of the algorithm for
+ * Lexicographical Permutations Generation, described in Knuth's "The Art of
+ * Computer Programming", Volume 4, Chapter 7, Section 7.2.1.2. The
+ * iteration order follows the lexicographical order. This means that
+ * the first permutation will be in ascending order, and the last will be in
+ * descending order.
+ *
+ * <p>Elements that compare equal are considered equal and no new permutations
+ * are created by swapping them.
+ *
+ * <p>An empty iterable has only one permutation, which is an empty list.
+ *
+ * @param elements the original iterable whose elements have to be permuted.
+ * @param comparator a comparator for the iterable's elements.
+ * @return an immutable {@link Collection} containing all the different
+ * permutations of the original iterable.
+ * @throws NullPointerException If the specified iterable is null, has any
+ * null elements, or if the specified comparator is null.
+ * @since 12.0
+ */
+ @Beta public static <E> Collection<List<E>> orderedPermutations(
+ Iterable<E> elements, Comparator<? super E> comparator) {
+ return new OrderedPermutationCollection<E>(elements, comparator);
+ }
+
+ private static final class OrderedPermutationCollection<E>
+ extends AbstractCollection<List<E>> {
+ final ImmutableList<E> inputList;
+ final Comparator<? super E> comparator;
+ final int size;
+
+ OrderedPermutationCollection(Iterable<E> input,
+ Comparator<? super E> comparator) {
+ this.inputList = Ordering.from(comparator).immutableSortedCopy(input);
+ this.comparator = comparator;
+ this.size = calculateSize(inputList, comparator);
+ }
+
+ /**
+ * The number of permutations with repeated elements is calculated as
+ * follows:
+ * <ul>
+ * <li>For an empty list, it is 1 (base case).</li>
+ * <li>When r numbers are added to a list of n-r elements, the number of
+ * permutations is increased by a factor of (n choose r).</li>
+ * </ul>
+ */
+ private static <E> int calculateSize(
+ List<E> sortedInputList, Comparator<? super E> comparator) {
+ long permutations = 1;
+ int n = 1;
+ int r = 1;
+ while (n < sortedInputList.size()) {
+ int comparison = comparator.compare(
+ sortedInputList.get(n - 1), sortedInputList.get(n));
+ if (comparison < 0) {
+ // We move to the next non-repeated element.
+ permutations *= binomial(n, r);
+ r = 0;
+ if (!isPositiveInt(permutations)) {
+ return Integer.MAX_VALUE;
+ }
+ }
+ n++;
+ r++;
+ }
+ permutations *= binomial(n, r);
+ if (!isPositiveInt(permutations)) {
+ return Integer.MAX_VALUE;
+ }
+ return (int) permutations;
+ }
+
+ @Override public int size() {
+ return size;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public Iterator<List<E>> iterator() {
+ return new OrderedPermutationIterator<E>(inputList, comparator);
+ }
+
+ @Override public boolean contains(@Nullable Object obj) {
+ if (obj instanceof List) {
+ List<?> list = (List<?>) obj;
+ return isPermutation(inputList, list);
+ }
+ return false;
+ }
+
+ @Override public String toString() {
+ return "orderedPermutationCollection(" + inputList + ")";
+ }
+ }
+
+ private static final class OrderedPermutationIterator<E>
+ extends AbstractIterator<List<E>> {
+
+ List<E> nextPermutation;
+ final Comparator<? super E> comparator;
+
+ OrderedPermutationIterator(List<E> list,
+ Comparator<? super E> comparator) {
+ this.nextPermutation = Lists.newArrayList(list);
+ this.comparator = comparator;
+ }
+
+ @Override protected List<E> computeNext() {
+ if (nextPermutation == null) {
+ return endOfData();
+ }
+ ImmutableList<E> next = ImmutableList.copyOf(nextPermutation);
+ calculateNextPermutation();
+ return next;
+ }
+
+ void calculateNextPermutation() {
+ int j = findNextJ();
+ if (j == -1) {
+ nextPermutation = null;
+ return;
+ }
+
+ int l = findNextL(j);
+ Collections.swap(nextPermutation, j, l);
+ int n = nextPermutation.size();
+ Collections.reverse(nextPermutation.subList(j + 1, n));
+ }
+
+ int findNextJ() {
+ for (int k = nextPermutation.size() - 2; k >= 0; k--) {
+ if (comparator.compare(nextPermutation.get(k),
+ nextPermutation.get(k + 1)) < 0) {
+ return k;
+ }
+ }
+ return -1;
+ }
+
+ int findNextL(int j) {
+ E ak = nextPermutation.get(j);
+ for (int l = nextPermutation.size() - 1; l > j; l--) {
+ if (comparator.compare(ak, nextPermutation.get(l)) < 0) {
+ return l;
+ }
+ }
+ throw new AssertionError("this statement should be unreachable");
+ }
+ }
+
+ /**
+ * Returns a {@link Collection} of all the permutations of the specified
+ * {@link Collection}.
+ *
+ * <p><i>Notes:</i> This is an implementation of the Plain Changes algorithm
+ * for permutations generation, described in Knuth's "The Art of Computer
+ * Programming", Volume 4, Chapter 7, Section 7.2.1.2.
+ *
+ * <p>If the input list contains equal elements, some of the generated
+ * permutations will be equal.
+ *
+ * <p>An empty collection has only one permutation, which is an empty list.
+ *
+ * @param elements the original collection whose elements have to be permuted.
+ * @return an immutable {@link Collection} containing all the different
+ * permutations of the original collection.
+ * @throws NullPointerException if the specified collection is null or has any
+ * null elements.
+ * @since 12.0
+ */
+ @Beta public static <E> Collection<List<E>> permutations(
+ Collection<E> elements) {
+ return new PermutationCollection<E>(ImmutableList.copyOf(elements));
+ }
+
+ private static final class PermutationCollection<E>
+ extends AbstractCollection<List<E>> {
+ final ImmutableList<E> inputList;
+
+ PermutationCollection(ImmutableList<E> input) {
+ this.inputList = input;
+ }
+
+ @Override public int size() {
+ return IntMath.factorial(inputList.size());
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public Iterator<List<E>> iterator() {
+ return new PermutationIterator<E>(inputList);
+ }
+
+ @Override public boolean contains(@Nullable Object obj) {
+ if (obj instanceof List) {
+ List<?> list = (List<?>) obj;
+ return isPermutation(inputList, list);
+ }
+ return false;
+ }
+
+ @Override public String toString() {
+ return "permutations(" + inputList + ")";
+ }
+ }
+
+ private static class PermutationIterator<E>
+ extends AbstractIterator<List<E>> {
+ final List<E> list;
+ final int[] c;
+ final int[] o;
+ int j;
+
+ PermutationIterator(List<E> list) {
+ this.list = new ArrayList<E>(list);
+ int n = list.size();
+ c = new int[n];
+ o = new int[n];
+ for (int i = 0; i < n; i++) {
+ c[i] = 0;
+ o[i] = 1;
+ }
+ j = Integer.MAX_VALUE;
+ }
+
+ @Override protected List<E> computeNext() {
+ if (j <= 0) {
+ return endOfData();
+ }
+ ImmutableList<E> next = ImmutableList.copyOf(list);
+ calculateNextPermutation();
+ return next;
+ }
+
+ void calculateNextPermutation() {
+ j = list.size() - 1;
+ int s = 0;
+
+ // Handle the special case of an empty list. Skip the calculation of the
+ // next permutation.
+ if (j == -1) {
+ return;
+ }
+
+ while (true) {
+ int q = c[j] + o[j];
+ if (q < 0) {
+ switchDirection();
+ continue;
+ }
+ if (q == j + 1) {
+ if (j == 0) {
+ break;
+ }
+ s++;
+ switchDirection();
+ continue;
+ }
+
+ Collections.swap(list, j - c[j] + s, j - q + s);
+ c[j] = q;
+ break;
+ }
+ }
+
+ void switchDirection() {
+ o[j] = -o[j];
+ j--;
+ }
+ }
+
+ /**
+ * Returns {@code true} if the second list is a permutation of the first.
+ */
+ private static boolean isPermutation(List<?> first,
+ List<?> second) {
+ if (first.size() != second.size()) {
+ return false;
+ }
+ Multiset<?> firstSet = HashMultiset.create(first);
+ Multiset<?> secondSet = HashMultiset.create(second);
+ return firstSet.equals(secondSet);
+ }
+
+ private static boolean isPositiveInt(long n) {
+ return n >= 0 && n <= Integer.MAX_VALUE;
+ }
+}