📄 collectionutils.java
字号:
/*
* Copyright 2001-2005 The Apache Software Foundation
*
* 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 org.apache.commons.collections;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections.collection.PredicatedCollection;
import org.apache.commons.collections.collection.SynchronizedCollection;
import org.apache.commons.collections.collection.TransformedCollection;
import org.apache.commons.collections.collection.TypedCollection;
import org.apache.commons.collections.collection.UnmodifiableBoundedCollection;
import org.apache.commons.collections.collection.UnmodifiableCollection;
/**
* Provides utility methods and decorators for {@link Collection} instances.
*
* @since Commons Collections 1.0
* @version $Revision: 348013 $ $Date: 2005-11-21 23:24:45 +0000 (Mon, 21 Nov 2005) $
*
* @author Rodney Waldhoff
* @author Paul Jack
* @author Stephen Colebourne
* @author Steve Downey
* @author Herve Quiroz
* @author Peter KoBek
* @author Matthew Hawthorne
* @author Janek Bogucki
* @author Phil Steitz
* @author Steven Melzer
* @author Jon Schewe
* @author Neil O'Toole
* @author Stephen Smith
*/
public class CollectionUtils {
/** Constant to avoid repeated object creation */
private static Integer INTEGER_ONE = new Integer(1);
/**
* An empty unmodifiable collection.
* The JDK provides empty Set and List implementations which could be used for
* this purpose. However they could be cast to Set or List which might be
* undesirable. This implementation only implements Collection.
*/
public static final Collection EMPTY_COLLECTION = UnmodifiableCollection.decorate(new ArrayList());
/**
* <code>CollectionUtils</code> should not normally be instantiated.
*/
public CollectionUtils() {
}
/**
* Returns a {@link Collection} containing the union
* of the given {@link Collection}s.
* <p>
* The cardinality of each element in the returned {@link Collection}
* will be equal to the maximum of the cardinality of that element
* in the two given {@link Collection}s.
*
* @param a the first collection, must not be null
* @param b the second collection, must not be null
* @return the union of the two collections
* @see Collection#addAll
*/
public static Collection union(final Collection a, final Collection b) {
ArrayList list = new ArrayList();
Map mapa = getCardinalityMap(a);
Map mapb = getCardinalityMap(b);
Set elts = new HashSet(a);
elts.addAll(b);
Iterator it = elts.iterator();
while(it.hasNext()) {
Object obj = it.next();
for(int i=0,m=Math.max(getFreq(obj,mapa),getFreq(obj,mapb));i<m;i++) {
list.add(obj);
}
}
return list;
}
/**
* Returns a {@link Collection} containing the intersection
* of the given {@link Collection}s.
* <p>
* The cardinality of each element in the returned {@link Collection}
* will be equal to the minimum of the cardinality of that element
* in the two given {@link Collection}s.
*
* @param a the first collection, must not be null
* @param b the second collection, must not be null
* @return the intersection of the two collections
* @see Collection#retainAll
* @see #containsAny
*/
public static Collection intersection(final Collection a, final Collection b) {
ArrayList list = new ArrayList();
Map mapa = getCardinalityMap(a);
Map mapb = getCardinalityMap(b);
Set elts = new HashSet(a);
elts.addAll(b);
Iterator it = elts.iterator();
while(it.hasNext()) {
Object obj = it.next();
for(int i=0,m=Math.min(getFreq(obj,mapa),getFreq(obj,mapb));i<m;i++) {
list.add(obj);
}
}
return list;
}
/**
* Returns a {@link Collection} containing the exclusive disjunction
* (symmetric difference) of the given {@link Collection}s.
* <p>
* The cardinality of each element <i>e</i> in the returned {@link Collection}
* will be equal to
* <tt>max(cardinality(<i>e</i>,<i>a</i>),cardinality(<i>e</i>,<i>b</i>)) - min(cardinality(<i>e</i>,<i>a</i>),cardinality(<i>e</i>,<i>b</i>))</tt>.
* <p>
* This is equivalent to
* <tt>{@link #subtract subtract}({@link #union union(a,b)},{@link #intersection intersection(a,b)})</tt>
* or
* <tt>{@link #union union}({@link #subtract subtract(a,b)},{@link #subtract subtract(b,a)})</tt>.
*
* @param a the first collection, must not be null
* @param b the second collection, must not be null
* @return the symmetric difference of the two collections
*/
public static Collection disjunction(final Collection a, final Collection b) {
ArrayList list = new ArrayList();
Map mapa = getCardinalityMap(a);
Map mapb = getCardinalityMap(b);
Set elts = new HashSet(a);
elts.addAll(b);
Iterator it = elts.iterator();
while(it.hasNext()) {
Object obj = it.next();
for(int i=0,m=((Math.max(getFreq(obj,mapa),getFreq(obj,mapb)))-(Math.min(getFreq(obj,mapa),getFreq(obj,mapb))));i<m;i++) {
list.add(obj);
}
}
return list;
}
/**
* Returns a new {@link Collection} containing <tt><i>a</i> - <i>b</i></tt>.
* The cardinality of each element <i>e</i> in the returned {@link Collection}
* will be the cardinality of <i>e</i> in <i>a</i> minus the cardinality
* of <i>e</i> in <i>b</i>, or zero, whichever is greater.
*
* @param a the collection to subtract from, must not be null
* @param b the collection to subtract, must not be null
* @return a new collection with the results
* @see Collection#removeAll
*/
public static Collection subtract(final Collection a, final Collection b) {
ArrayList list = new ArrayList( a );
for (Iterator it = b.iterator(); it.hasNext();) {
list.remove(it.next());
}
return list;
}
/**
* Returns <code>true</code> iff at least one element is in both collections.
* <p>
* In other words, this method returns <code>true</code> iff the
* {@link #intersection} of <i>coll1</i> and <i>coll2</i> is not empty.
*
* @param coll1 the first collection, must not be null
* @param coll2 the first collection, must not be null
* @return <code>true</code> iff the intersection of the collections is non-empty
* @since 2.1
* @see #intersection
*/
public static boolean containsAny(final Collection coll1, final Collection coll2) {
if (coll1.size() < coll2.size()) {
for (Iterator it = coll1.iterator(); it.hasNext();) {
if (coll2.contains(it.next())) {
return true;
}
}
} else {
for (Iterator it = coll2.iterator(); it.hasNext();) {
if (coll1.contains(it.next())) {
return true;
}
}
}
return false;
}
/**
* Returns a {@link Map} mapping each unique element in the given
* {@link Collection} to an {@link Integer} representing the number
* of occurrences of that element in the {@link Collection}.
* <p>
* Only those elements present in the collection will appear as
* keys in the map.
*
* @param coll the collection to get the cardinality map for, must not be null
* @return the populated cardinality map
*/
public static Map getCardinalityMap(final Collection coll) {
Map count = new HashMap();
for (Iterator it = coll.iterator(); it.hasNext();) {
Object obj = it.next();
Integer c = (Integer) (count.get(obj));
if (c == null) {
count.put(obj,INTEGER_ONE);
} else {
count.put(obj,new Integer(c.intValue() + 1));
}
}
return count;
}
/**
* Returns <tt>true</tt> iff <i>a</i> is a sub-collection of <i>b</i>,
* that is, iff the cardinality of <i>e</i> in <i>a</i> is less
* than or equal to the cardinality of <i>e</i> in <i>b</i>,
* for each element <i>e</i> in <i>a</i>.
*
* @param a the first (sub?) collection, must not be null
* @param b the second (super?) collection, must not be null
* @return <code>true</code> iff <i>a</i> is a sub-collection of <i>b</i>
* @see #isProperSubCollection
* @see Collection#containsAll
*/
public static boolean isSubCollection(final Collection a, final Collection b) {
Map mapa = getCardinalityMap(a);
Map mapb = getCardinalityMap(b);
Iterator it = a.iterator();
while (it.hasNext()) {
Object obj = it.next();
if (getFreq(obj, mapa) > getFreq(obj, mapb)) {
return false;
}
}
return true;
}
/**
* Returns <tt>true</tt> iff <i>a</i> is a <i>proper</i> sub-collection of <i>b</i>,
* that is, iff the cardinality of <i>e</i> in <i>a</i> is less
* than or equal to the cardinality of <i>e</i> in <i>b</i>,
* for each element <i>e</i> in <i>a</i>, and there is at least one
* element <i>f</i> such that the cardinality of <i>f</i> in <i>b</i>
* is strictly greater than the cardinality of <i>f</i> in <i>a</i>.
* <p>
* The implementation assumes
* <ul>
* <li><code>a.size()</code> and <code>b.size()</code> represent the
* total cardinality of <i>a</i> and <i>b</i>, resp. </li>
* <li><code>a.size() < Integer.MAXVALUE</code></li>
* </ul>
*
* @param a the first (sub?) collection, must not be null
* @param b the second (super?) collection, must not be null
* @return <code>true</code> iff <i>a</i> is a <i>proper</i> sub-collection of <i>b</i>
* @see #isSubCollection
* @see Collection#containsAll
*/
public static boolean isProperSubCollection(final Collection a, final Collection b) {
return (a.size() < b.size()) && CollectionUtils.isSubCollection(a,b);
}
/**
* Returns <tt>true</tt> iff the given {@link Collection}s contain
* exactly the same elements with exactly the same cardinalities.
* <p>
* That is, iff the cardinality of <i>e</i> in <i>a</i> is
* equal to the cardinality of <i>e</i> in <i>b</i>,
* for each element <i>e</i> in <i>a</i> or <i>b</i>.
*
* @param a the first collection, must not be null
* @param b the second collection, must not be null
* @return <code>true</code> iff the collections contain the same elements with the same cardinalities.
*/
public static boolean isEqualCollection(final Collection a, final Collection b) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -