📄 collectionutils.java
字号:
/*
* Copyright 1999-2004 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.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.NoSuchElementException;
import java.util.Set;
import org.apache.commons.collections.iterators.ArrayIterator;
import org.apache.commons.collections.iterators.EnumerationIterator;
/**
* A set of {@link Collection} related utility methods.
*
* @since 1.0
* @author Rodney Waldhoff
* @author Paul Jack
* @author Stephen Colebourne
* @author Steve Downey
* @version $Revision: 1.18.2.2 $ $Date: 2004/05/22 12:14:02 $
*/
public class CollectionUtils {
/**
* The empty iterator (immutable).
* @deprecated use IteratorUtils.EMPTY_ITERATOR
*/
public static final Iterator EMPTY_ITERATOR = IteratorUtils.EMPTY_ITERATOR;
/**
* Please don't ever instantiate a <code>CollectionUtils</code>.
*/
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.
*
* @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.
*
* @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>.
*/
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 {@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.
*
* @see Collection#removeAll
*/
public static Collection subtract(final Collection a, final Collection b) {
ArrayList list = new ArrayList( a );
Iterator it = b.iterator();
while(it.hasNext()) {
list.remove(it.next());
}
return list;
}
/**
* Returns <code>true</code> iff some element of <i>a</i>
* is also an element of <i>b</i> (or, equivalently, if
* some element of <i>b</i> is also an element of <i>a</i>).
* In other words, this method returns <code>true</code>
* iff the {@link #intersection} of <i>a</i> and <i>b</i>
* is not empty.
* @since 2.1
* @param a a non-<code>null</code> Collection
* @param b a non-<code>null</code> Collection
* @return <code>true</code> iff the intersection of <i>a</i> and <i>b</i> is non-empty
* @see #intersection
*/
public static boolean containsAny(final Collection a, final Collection b) {
// TO DO: we may be able to optimize this by ensuring either a or b
// is the larger of the two Collections, but I'm not sure which.
for(Iterator iter = a.iterator(); iter.hasNext();) {
if(b.contains(iter.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 occurances of that element
* in the {@link Collection}.
* An entry that maps to <tt>null</tt> indicates that the
* element does not appear in the given {@link Collection}.
*/
public static Map getCardinalityMap(final Collection col) {
HashMap count = new HashMap();
Iterator it = col.iterator();
while(it.hasNext()) {
Object obj = it.next();
Integer c = (Integer)(count.get(obj));
if(null == c) {
count.put(obj,new Integer(1));
} 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>.
*
* @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>.
*
* @see #isSubCollection
* @see Collection#containsAll
*/
public static boolean isProperSubCollection(final Collection a, final Collection b) {
// XXX optimize me!
return CollectionUtils.isSubCollection(a,b) && (!(CollectionUtils.isEqualCollection(a,b)));
}
/**
* Returns <tt>true</tt> iff the given {@link Collection}s contain
* exactly the same elements with exactly the same cardinality.
* <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>.
*/
public static boolean isEqualCollection(final Collection a, final Collection b) {
if(a.size() != b.size()) {
return false;
} else {
Map mapa = getCardinalityMap(a);
Map mapb = getCardinalityMap(b);
if(mapa.size() != mapb.size()) {
return false;
} else {
Iterator it = mapa.keySet().iterator();
while(it.hasNext()) {
Object obj = it.next();
if(getFreq(obj,mapa) != getFreq(obj,mapb)) {
return false;
}
}
return true;
}
}
}
/**
* Returns the number of occurrences of <i>obj</i>
* in <i>col</i>.
*/
public static int cardinality(Object obj, final Collection col) {
int count = 0;
Iterator it = col.iterator();
while(it.hasNext()) {
Object elt = it.next();
if((null == obj && null == elt) || obj.equals(elt)) {
count++;
}
}
return count;
}
/**
* Finds the first element in the given collection which matches the given predicate.
* <p>
* If the input collection or predicate is null, null is returned.
*
* @param collection the collection to search, may be null
* @param predicate the predicate to use, may be null
* @return the first element of the collection which matches the predicate or null if none could be found
*/
public static Object find(Collection collection, Predicate predicate) {
if (collection != null && predicate != null) {
for (Iterator iter = collection.iterator(); iter.hasNext();) {
Object item = iter.next();
if (predicate.evaluate(item)) {
return item;
}
}
}
return null;
}
/**
* Executes the given closure on each element in the collection.
* <p>
* If the input collection is null, there is no change made.
*
* @param collection the collection to get the input from, may be null
* @param closure the closure to perform, may not be null
* @throws NullPointerException if the closure is null
*/
public static void forAllDo(Collection collection, Closure closure) {
if (collection != null) {
for (Iterator iter = collection.iterator(); iter.hasNext();) {
Object element = iter.next();
closure.execute(element);
}
}
}
/**
* Filter the collection by applying a Predicate to each element. If the
* predicate returns false, remove the element.
* <p>
* If the input collection or predicate is null, there is no change made.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -