Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.google.common.collect.Multisets Maven / Gradle / Ivy
Go to download
Google Collections Library is a suite of new collections and collection-related goodness for Java 5.0
/*
* Copyright (C) 2007 Google Inc.
*
* 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 java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
/**
* Provides static utility methods for creating and working with {@link
* Multiset} instances.
*
* @author Kevin Bourrillion
* @author Mike Bostock
*/
public final class Multisets {
private static final Multiset> EMPTY_MULTISET = new EmptyMultiset();
private static final Multiset> IMMUTABLE_EMPTY_MULTISET =
unmodifiableMultiset(new EmptyMultiset());
private Multisets() {}
/**
* Creates an empty {@code HashMultiset} using the default initial capacity
* (16 distinct elements).
*/
public static HashMultiset newHashMultiset() {
return new HashMultiset();
}
/**
* Creates a {@code HashMultiset} containing the specified elements, using the
* default initial capacity (16 distinct elements).
*
* @param elements the elements that the multiset should contain
*/
public static HashMultiset newHashMultiset(E... elements) {
HashMultiset multiset = new HashMultiset();
Collections.addAll(multiset, elements);
return multiset;
}
/**
* Creates a {@code HashMultiset} containing the specified elements.
*
* @param elements the elements that the multiset should contain
*/
public static HashMultiset newHashMultiset(
Iterable extends E> elements) {
return new HashMultiset(elements);
}
/**
* Creates an empty {@code TreeMultiset} instance.
*
* @return a newly-created, initially-empty TreeMultiset
*/
@SuppressWarnings("unchecked") // allow ungenerified Comparable types
public static TreeMultiset newTreeMultiset() {
return new TreeMultiset();
}
/**
* Creates an empty {@code TreeMultiset} instance, sorted according to the
* specified comparator.
*
* @return a newly-created, initially-empty TreeMultiset
*/
public static TreeMultiset newTreeMultiset(Comparator super E> c) {
return new TreeMultiset(c);
}
/** Creates an empty {@code EnumMultiset}. */
public static > EnumMultiset newEnumMultiset(
Class type) {
return new EnumMultiset(type);
}
/**
* Creates an {@code EnumMultiset} containing the specified elements.
*
* @throws IllegalArgumentException if {@code elements} is empty
*/
public static > EnumMultiset newEnumMultiset(
Iterable elements) {
return new EnumMultiset(elements);
}
/**
* Creates an {@code EnumMultiset} containing the specified elements.
*
* @throws IllegalArgumentException if {@code elements} is empty
*/
public static > EnumMultiset newEnumMultiset(
E... elements) {
checkArgument(elements.length > 0,
"newEnumMultiset requires at least one element");
EnumMultiset multiset = newEnumMultiset(elements[0].getDeclaringClass());
Collections.addAll(multiset, elements);
return multiset;
}
/**
* Returns an unmodifiable view of the specified multiset. Query operations on
* the returned multiset "read through" to the specified multiset, and
* attempts to modify the returned multiset result in an
* {@link UnsupportedOperationException}.
*
* @param multiset the multiset for which an unmodifiable view is to be
* generated
* @return an unmodifiable view of the multiset
*/
public static Multiset unmodifiableMultiset(Multiset multiset) {
return new UnmodifiableMultiset(multiset);
}
private static class UnmodifiableMultiset extends ForwardingMultiset {
transient Set elementSet;
private UnmodifiableMultiset(Multiset delegate) {
super(delegate);
}
@Override public Set elementSet() {
Set es = elementSet;
return (es == null)
? elementSet = Collections.unmodifiableSet(super.elementSet())
: es;
}
transient Set> entrySet;
@Override public Set> entrySet() {
Set> es = entrySet;
return (es == null)
? entrySet = Collections.unmodifiableSet(super.entrySet())
: es;
}
@Override public Iterator iterator() {
return Iterators.unmodifiableIterator(super.iterator());
}
@Override public boolean add(E element) {
throw new UnsupportedOperationException();
}
@Override public boolean add(E element, int occurences) {
throw new UnsupportedOperationException();
}
@Override public boolean addAll(Collection extends E> elementsToAdd) {
throw new UnsupportedOperationException();
}
@Override public boolean remove(Object element) {
throw new UnsupportedOperationException();
}
@Override public int remove(Object element, int occurrences) {
throw new UnsupportedOperationException();
}
@Override public int removeAllOccurrences(Object element) {
throw new UnsupportedOperationException();
}
@Override public boolean removeAll(Collection> elementsToRemove) {
throw new UnsupportedOperationException();
}
@Override public boolean retainAll(Collection> elementsToRetain) {
throw new UnsupportedOperationException();
}
@Override public void clear() {
throw new UnsupportedOperationException();
}
private static final long serialVersionUID = 0;
}
/**
* Returns a synchronized (thread-safe) multiset backed by the specified
* multiset. In order to guarantee serial access, all access to the
* backing multiset must go through the returned multiset.
*
* It is imperative that the user manually synchronize on the returned
* multiset when iterating over any of its collection views:
*
*
Multiset<E> m = Multisets.synchronizedMultiset(
* new HashMultiset<E>());
* ...
* Set<E> s = m.elementSet(); // Needn't be in synchronized block
* ...
* synchronized (m) { // Synchronizing on m, not s!
* Iterator<E> i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
* }
*
* Failure to follow this advice may result in non-deterministic behavior.
*
* For a greater degree of concurrency, you may use a {@link
* ConcurrentMultiset}.
*
* @param multiset the multiset to be wrapped
* @return a synchronized view of the specified multiset
*/
public static Multiset synchronizedMultiset(Multiset multiset) {
return Synchronized.multiset(multiset, null);
}
/** Returns the empty multiset (immutable). This multiset is serializable. */
@SuppressWarnings("unchecked")
public static Multiset emptyMultiset() {
return (Multiset) EMPTY_MULTISET;
}
/** @see Multisets#emptyMultiset */
private static class EmptyMultiset extends AbstractCollection
implements Multiset, Serializable {
@Override public int size() {
return 0;
}
@Override public Iterator iterator() {
return Iterators.emptyIterator();
}
public int count(Object element) {
return 0;
}
public boolean add(E element, int occurrences) {
throw new UnsupportedOperationException();
}
/*
* The remove methods return 0, for consistency with
* Collections.emptySet().remove().
*/
public int remove(Object element, int occurrences) {
return 0;
}
public int removeAllOccurrences(Object element) {
return 0;
}
public Set elementSet() {
return Collections.emptySet();
}
public Set> entrySet() {
return Collections.emptySet();
}
@Override public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Multiset>)) {
return false;
}
return ((Multiset>) obj).isEmpty();
}
@Override public int hashCode() {
return 0;
}
@Override public String toString() {
return "[]";
}
private Object readResolve() {
return EMPTY_MULTISET; // preserve singleton property
}
private static final long serialVersionUID = -4387083049544049902L;
}
/**
* Returns an immutable multiset entry with the specified element and count.
*
* @param e the element to be associated with the returned entry
* @param n the count to be associated with the returned entry
* @throws IllegalArgumentException if {@code n} is negative
*/
public static Multiset.Entry immutableEntry(final E e, final int n) {
checkArgument(n >= 0);
return new AbstractMultisetEntry() {
public E getElement() {
return e;
}
public int getCount() {
return n;
}
};
}
/**
* Returns a multiset view of the specified set. The multiset is backed by the
* set, so changes to the set are reflected in the multiset, and vice versa.
* If the set is modified while an iteration over the multiset is in progress
* (except through the iterator's own {@code remove} operation) the results of
* the iteration are undefined.
*
* The multiset supports element removal, which removes the corresponding
* element from the set. It does not support the {@code add} or {@code addAll}
* operations.
*
*
The returned multiset will be serializable if the specified set is
* serializable.
*
* @param set the backing set for the returned multiset view
*/
public static Multiset forSet(Set set) {
return new SetMultiset(set);
}
/** @see Multisets#forSet */
private static class SetMultiset extends ForwardingCollection
implements Multiset, Serializable {
transient volatile Set elementSet;
transient volatile Set> entrySet;
SetMultiset(Set set) {
super(set);
}
@Override protected Set delegate() {
return (Set) super.delegate();
}
public int count(Object element) {
return delegate().contains(element) ? 1 : 0;
}
public boolean add(E element, int occurrences) {
throw new UnsupportedOperationException();
}
public int remove(Object element, int occurrences) {
if (occurrences == 0) {
return 0;
}
checkArgument(occurrences > 0);
return removeAllOccurrences(element);
}
public int removeAllOccurrences(Object element) {
return delegate().remove(element) ? 1 : 0;
}
public Set elementSet() {
if (elementSet == null) {
elementSet = new ElementSet();
}
return elementSet;
}
public Set> entrySet() {
if (entrySet == null) {
entrySet = new EntrySet();
}
return entrySet;
}
@Override public boolean add(E o) {
throw new UnsupportedOperationException();
}
@Override public boolean addAll(Collection extends E> c) {
throw new UnsupportedOperationException();
}
@Override public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Multiset>)) {
return false;
}
Multiset> m = (Multiset>) o;
return size() == m.size() && delegate().equals(m.elementSet());
}
@Override public int hashCode() {
int sum = 0;
for (E e : this) {
sum += ((e == null) ? 0 : e.hashCode()) ^ 1;
}
return sum;
}
/** @see SetMultiset#elementSet */
class ElementSet extends NonSerializableForwardingSet {
ElementSet() {
super(SetMultiset.this.delegate());
}
@Override public boolean add(E o) {
throw new UnsupportedOperationException();
}
@Override public boolean addAll(Collection extends E> c) {
throw new UnsupportedOperationException();
}
}
/** @see SetMultiset#entrySet */
class EntrySet extends AbstractSet> {
@Override public int size() {
return delegate().size();
}
@Override public Iterator> iterator() {
return new Iterator>() {
final Iterator elements = delegate().iterator();
public boolean hasNext() {
return elements.hasNext();
}
public Entry next() {
return immutableEntry(elements.next(), 1);
}
public void remove() {
elements.remove();
}
};
}
// TODO: faster contains, remove?
}
private static final long serialVersionUID = 7787490547740866319L;
}
/**
* Returns the expected number of distinct elements given the specified
* elements. The number of distinct elements is only computed if {@code
* elements} is an instance of {@code Multiset}; otherwise the default value
* of 11 is returned.
*/
static int inferDistinctElements(Iterable> elements) {
if (elements instanceof Multiset>) {
return ((Multiset>) elements).elementSet().size();
}
return 11; // initial capacity will be rounded up to 16
}
/**
* Returns an immutable empty {@code Multiset}. Equivalent to {@link
* Multisets#emptyMultiset}, except that the returned multiset's
* {@code remove} methods throw an {@link UnsupportedOperationException}.
*/
@SuppressWarnings("unchecked")
public static Multiset immutableMultiset() {
return (Multiset) IMMUTABLE_EMPTY_MULTISET;
}
/**
* Returns an immutable {@code Multiset} containing the specified elements.
*
* Unlike an unmodifiable multiset such as that returned by {@link
* Multisets#unmodifiableMultiset}, which provides a read-only view of an
* underlying multiset which may itself be mutable, an immutable
* multiset makes a copy of the original mappings, so that the returned
* multiset is guaranteed never to change. This is critical, for
* example, if the multiset is an element of a {@code HashSet} or a key in a
* {@code HashMap}.
*
* @param elements the elements that the returned multiset should contain
*/
public static Multiset immutableMultiset(E... elements) {
return (elements.length == 0)
? Multisets.immutableMultiset()
: unmodifiableMultiset(newHashMultiset(elements));
}
/**
* Returns a comparator that orders elements according to their increasing
* frequency in a multiset. For example, suppose {@code m} is a non-empty
* multiset of strings. Then:
*
* Collections.max(m.elementSet(), frequencyOrder(m));
*
* returns a string that occurs most frequently in {@code m}.
* (Warning: in this example, {@code Collections.max} throws
* {@code NoSuchElementException} when {@code m} is empty.)
*
* The returned comparator is a view into the backing multiset, so the
* comparator's behavior will change if the backing multiset changes. This can
* be dangerous; for example, if the comparator is used by a {@code TreeSet}
* and the backing multiset changes, the behavior of the {@code TreeSet}
* becomes undefined. Use a copy of the multiset to isolate against such
* changes when necessary.
*
* @param multiset the multiset specifying the frequencies of the objects to
* compare
*/
public static Comparator frequencyOrder(Multiset> multiset) {
return new FrequencyOrder(multiset);
}
/** @see Multisets#frequencyOrder(Multiset) */
private static class FrequencyOrder implements SerializableComparator {
final Multiset> multiset;
FrequencyOrder(Multiset> multiset) {
this.multiset = checkNotNull(multiset);
}
public int compare(T left, T right) {
int leftCount = multiset.count(left);
int rightCount = multiset.count(right);
return Comparators.compare(leftCount, rightCount);
}
@Override public boolean equals(Object object) {
if (object instanceof FrequencyOrder>) {
FrequencyOrder> that = (FrequencyOrder>) object;
return (this.multiset).equals(that.multiset);
}
return false;
}
@Override public int hashCode() {
return multiset.hashCode();
}
private static final long serialVersionUID = -6424503578659119387L;
}
}