比較兩個List是否相等(相同元素)

最近做的一個項目,獲取檢查兩個request中的選項是否一樣,所以碰到了校驗兩個List是否相等的問題,所以在此yy了一下。

我們看看如何比較兩個數組相等。數組是一個連續的內存空間,所以一般來說,兩個數組相等,就是意味着他們有相同的長度,相同的元素,以及相同的順序。我們看看JDK的Arrays.equals()實現就一目瞭然了。

    public static boolean equals(int[] a, int[] a2) {
        if (a==a2) return true;
        if (a==null || a2==null) return false;
        int length = a.length;
        if (a2.length != length) return false;
        for (int i=0; i<length; i++)
            if (a[i] != a2[i]) return false;
        return true;
    }

         大致分成下面4個步驟:

1. 檢查是否指向同一個地址(不同引用);

2. 非空檢查;

3. 長度檢查;

4. 順序和對應的元素相等檢查。(依次比較,只要一個不等就返回false)

        

而對於List來說,沒有固定的順序(ArrayList底層是數組,可以用數組的比較方法;但是其他的List,如LinkedList,就不一樣了。),或者說順序對List來說不是一個重要的屬性。所以可以考慮其他方式來檢查兩個List是不是包含相同的元素。

如JDK的Collection.containsAll(),只是是對每個元素進行contains()操作。但是List允許重複的元素,所以這裏無法比較重複元素的數量:

    public boolean containsAll(Collection<?> c) {
        for (Object e : c)
            if (!contains(e))
                return false;
        return true;
    }

 

那麼,如何對無序的元素進行equal比較呢?

比較簡便直觀的方法,就是分別對兩個list排序,然後一個一個比較,只要不相等,則返回false,如果全部都相等,則返回true。

if (a.size() !=b.size())
    return false;
Collections.sort(a);
Collections.sort(b);
for (int i = 0; i <a.size(); i++) {
    if(!a.get(i).equals(b.get(i)))
       return false;
}
return true;

 

但是這樣兩次排序,效率還是比較低的。所以可以通過Map來實現:

先存入HashMap,key爲元素,value爲出現的次數,然後再逐個元素比較出現的次數,這樣能確保元素都包含,而且出現次數相同。

如下代碼所示,具體可以參考org.apache.commons.collections.CollectionUtils.isEqualCollection() 。(CollectionUtils中大量使用了getCardinalityMap()的特性)

private static final Integer INTEGER_ONE = 1;
public static boolean isEqualCollection(Collection a, Collection b){
    if (a.size() !=b.size()) {  // size是最簡單的相等條件
       return false;
    }
    Map mapa = getCardinalityMap(a); 
    Map mapb = getCardinalityMap(b);
   
    // 轉換map後,能去掉重複的,這時候size就是非重複項,也是先決條件
    if (mapa.size() !=mapb.size()) {  
       return false;
    }
    Iterator it =mapa.keySet().iterator();
    while (it.hasNext()) {
       Object obj = it.next();
       // 查詢同一個obj,首先兩邊都要有,而且還要校驗重複個數,就是map.value
       if (getFreq(obj,mapa) != getFreq(obj, mapb)) {
           return false;
       }
    }
    return true;
}
/**
 * 以obj爲key,可以防止重複,如果重複就value++
 * 這樣實際上記錄了元素以及出現的次數
 */
public static Map getCardinalityMap(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, newInteger(c.intValue() + 1));
       }
    }
    return count;
}
private static final int getFreq(Objectobj, Map freqMap) {
    Integer count =(Integer) freqMap.get(obj);
    if (count != null) {
       return count.intValue();
    }
    return 0;
}


發佈了44 篇原創文章 · 獲贊 11 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章