簡體   English   中英

自定義IEqualityComparer可以比使用.Where()+ .Any()更快地從兩個列表中獲取不同的對象

[英]Custom IEqualityComparer to get distinct objects from two lists faster than using .Where() + .Any()

所以我有兩個對象列表,對象具有多個字段,但是我只想基於其中兩個來區分它們。

為了給您提供圖片,對象KeyAndValue由字段Key和Tag組成,因此:

list1 = { obj1(key=1,tag=A), obj2(key=2,tag=A) }
list2 = { obj3(key=1,tag=A), obj4(key=2,tag=B) }

我目前正在使用:

list1.Where(x => !list2.Any(y => y.key == x.key)).ToList();

正確的結果是:obj1,obj2和obj4,因為obj3與obj1具有相同的鍵和標記

我要完成的工作是加快此過程,因為處理許多對象需要很長時間。 我發現自定義IEqualityComparer可以在這里提供幫助,因此我根據MS Specification編寫了自己的代碼,如下所示:

class KeyComparer : IEqualityComparer<KeyAndValue>
{
    public bool Equals(KeyAndValue x, KeyAndValue y)
    {
        if (Object.ReferenceEquals(x, y))
            return true;
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;
        return x.key == y.key && x.tag == y.tag;
    }
    public int GetHashCode(KeyAndValue keyAndValue)
    {
        if (Object.ReferenceEquals(keyAndValue, null))
            return 0;
        int hashKeyAndValueKey = keyAndValue.key == null ? 0 : keyAndValue.key.GetHashCode();
        int hashKeyAndValueTag = keyAndValue.tag == null ? 0 : keyAndValue.tag.GetHashCode();
        return hashKeyAndValueKey ^ hashKeyAndValueTag;
    }
}

我這樣使用它:

list1.Except(list2, new KeyComparer()).ToList();

不幸的是,它僅從list2中刪除重復項。 似乎它甚至都沒有觸及list1,而且我不知道這是我的自定義比較器的問題,還是我使用它的方式,或者我應該使用其他方法。 我一直在尋找其他問題,但找不到有效的答案(或至少我實際上知道如何正確實施的答案)。

我認為您不需要Except 您想兩者都有不同的價值嗎?

var distinctValues = list1.Union(list2).Distinct();

您需要在KeyAndValue實現GetHashCode / Equals或使用比較器通過鍵和值比較對象。


(舊東西在下面)

不知道我是否正確理解了這個問題。 可能是您不認識到,除了創建一個新的IEnumerable並ToList一個新的List之外?

嘗試:

var list1AdditionalItems = list1.Except(list2, new KeyComparer()).ToList();

可能還有:

var list2AdditionalItems = list2.Except(list1, new KeyComparer()).ToList();

另一個觀察。 在此代碼中:

list1.Where(x => !list2.Any(y => y.key == x.key)).ToList();

您只需檢查密鑰。 如果您想要這種行為,則應相應地編寫比較器:

class KeyComparer : IEqualityComparer<KeyAndValue>
{
    public bool Equals(KeyAndValue x, KeyAndValue y)
    {
        if (ReferenceEquals(x, y))
            return true;
        if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
            return false;
        return x.key == y.key;
    }
    public int GetHashCode(KeyAndValue keyAndValue)
    {
        if (ReferenceEquals(keyAndValue, null))
            return 0;
        return keyAndValue.key == null ? 0 : keyAndValue.key.GetHashCode();
    }
}

最后但並非最不重要的一點:當您需要性能時,請考慮使用字典。

正如Stefan Steinegger(在此我非常感謝所付出的努力和所花費的時間)在第一條評論中提到,我的方法均未返回obj4時,我發現了一個問題,並決定實施完全不同的方法。 現在,我的KeyAndValue類還具有一個int Hash字段,當一個構造函數稱為Hash字段時,將key.GetHashCode() ^ tag.GetHashCode()填充。 它簡化了比較,因為現在我首先將list1與list2組合在一起,然后通過以下方式發送它: CombinedList.GroupBy(x => x.Hash).Select(y => y.First()).ToList(); 結果似乎是正確的:)

暫無
暫無

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

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