簡體   English   中英

比較兩個List的對象值而不實現equals()的有效方法?

[英]Efficient way to Compare Two List's object values without implenmenting equals()?

我在這里有兩個類似的問題:

  1. Java比較兩個List的對象值?
  2. Java ArrayList - 如何判斷兩個列表是否相等,順序無關緊要?

但我有一個很糟糕的情況,使這個問題有點復雜。 我需要比較的對象來自一個古老的第三方jar,它沒有equals()函數。 我擔心修改它的代碼。

我想出的一個解決方案是構建另外兩個列表,它們的值是原始列表的串聯。 問題2與問題2沒有區別。

但我仍然想知道是否有更好的方法?

嘗試使用Apache Commons isEqualCollection(Collection a,Collection b,Equator equator) ,您仍然需要以與編寫equals override相同的方式實現Equator。

您也可以嘗試這個 ,這是與Apache Commons相同的算法,但有一些性能改進。

第1點:參見Kayaman的評論(提供equals函數的包裝類)。

第2點:此包裝類可能另外提供lessThan函數,對元素強加絕對順序。 然后,您可以對兩個列表進行排序,然后逐個元素地進行比較。 這比嘗試在另一個列表中識別一個列表的每個元素更有效,並且還優雅地處理重復的問題。

例如,快速排序的實現示例可以在互聯網上找到,例如這里

首先,您需要一個表現良好的對象規范表示。 創建一個名為MyCustomObject的類(希望你能想到一個更好的名字),它包含原始對象中最相關的屬性,並實現equals(),hashCode()和toString()。 編寫一個構造函數或工廠方法,從原始對象創建MyCustomObject實例。 現在將您的列表轉換為地圖:

List<OriginalObject> list = // wherever you get your list from
Map<MyCustomObject> map = list.stream()
                              .collect(
                                 Collectors.toMap(
                                    MyCustomObject::new,
                                    (oo)->oo)
                               );

對兩個列表執行此操作,並比較兩個映射的keySet()。

為了說明Kayaman的答案,你可以這樣做:

public class EqualsWrapper {
    private final Object delegate;

    public EqualsWrapper(Object toWrap) {
        delegate = toWrap;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((delegate == null) ? 0 : delegate.toString().hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        EqualsWrapper other = (EqualsWrapper) obj;
        return other.toString().equals(obj.toString());
    }
}

public static boolean areListsEqual(List list1, List list2){
    Set<EqualsWrapper> l_set1 = list1.stream().map(e -> new EqualsWrapper(e)).collect(Collectors.toSet());
    Set<EqualsWrapper> l_set2 = list2.stream().map(e -> new EqualsWrapper(e)).collect(Collectors.toSet());

    return l_set1.equals(l_set2);
}

但是,如果您擁有非常大的列表並且很有可能它們不相等,那么復制整個列表可能不是最佳選擇。 你也可以遵循這個立場:

public static boolean areListsEqual(List list1, List list2){
    return list1.stream().map(e -> new EqualsWrapper(e)).allMatch(e -> list2.stream().map(e -> new EqualsWrapper(e)).anyMatch(e2 -> e2.equals(e)));
}

如果沒有匹配,你會更快地破壞,但有可能失去有關潛在重復的信息。

我的方法還需要實現equals方法,但是每當使用新字段更新對象時,您都不希望更新equals方法。

嘗試一下 ,我相信,這種方法可以接受。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM