2011-09-08 46 views
4

我想計算集合之間的差異。當使用CollectionUtils.subtract()進行自定義比較時,我需要重寫對象的equals()方法。但是如果我需要比較相同類型但不同比較標準的對象集合呢?比較器接口怎麼樣,它在這裏看起來非常適合? AFAIK比較器主要用於分類。沒有使用比較器進行減法的方法嗎?如何用比較器接口減去集合而不是覆蓋等於

+0

我們_override_'等於',而不是_overwrite_它! :) – adarshr

+0

@adarshr當然,謝謝你的提示。我更新了標題 – mamuesstack

回答

2

如果您有一個ArrayList,多次刪除可能比採取副本更昂貴。

List<Type> list = /* ArrayList */ 
Set<Type> toRemove = /* HashSet */ 
List<Type> copy = new ArrayList<Type>(list.size()); 
for(Type t: list) 
    if(!toRemove.contains(t)) 
    copy.add(t); 
list = copy; 

個人而言,我會用一個循環。它可能會更短,更清晰。

Collection<Type> collection = 

for(Iterator<Type> i=collection.iterator(); i.hasNext();) 
    if (i.next() is to be removed) 
     i.remove(); 

顯式使用Iterator的原因是使用Iterator.remove(),它避免了ConcurrentModificationException。避免它的另一種方法是使用可能優選的集合的副本。

for(Type t : new ArrayList<Type>(collection)) 
    if (t is to be removed) 
     collection.remove(t); 

這表現不佳,但可能表現不錯。

+0

這可能會導致異常,因爲在循環播放時修改集合,因此您必須複製 –

+1

如果使用'Iterator.remove()',則不適用。如果您在另一個線程中修改集合,則無論是否複製,都可能會遇到異常。 –

+2

@Frank Meulenaar,我已經包括了你所提出的替代方案,但是兩者都可以工作。 –

3
static <Type> Collection<Type> subtract(Collection<Type> a, Collection<Type> b, Comparator<Type> c) { 
    Set<Type> subtrahend = new TreeSet<Type>(c); 
    subtrahend.addAll(b); 
    Collection<Type> result = new ArrayList<Type>(); 
    for (Type item: a) { 
     if (!subtrahend.contains(item)) result.add(item); 
    } 
    return result; 
} 

subtrahent樹集是沒有必要的,但將改善大b性能。

+0

這裏的比較器僅用於排序收集項目。 removeAll()再次使用類型的equals方法,而不是比較器提供的任何邏輯 – mamuesstack

+0

確定嗎? TreeSet內部使用一個TreeMap,其中'remove()'依賴'getEntry()',它使用比較器。 – Cephalopod

+0

似乎'比較器不符合等號'equals()'的'TreeSet'遇到'removeAll()'的問題。請看看[這裏](http://lingpipe-blog.com/category/java/page/5/)。 – mamuesstack