2013-01-08 32 views
3

我有兩個包含相同類型對象的集合,兩個集合都有大約40K個對象。使用40K對象找出2個系列的差異

每個集合包含對象的代碼基本上就像一本字典,除了我已經覆蓋了equals和散列函數:

public class MyClass: IEquatable<MyClass> 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 

    public override bool Equals(object obj) 
    { 
     return obj is MyClass && this.Equals((MyClass)obj); 
    } 

    public bool Equals(MyClass ot) 
    { 
     if (ReferenceEquals(this, ot)) 
     { 
      return true; 
     } 

     return 
     ot.ID.Equals(this.ID) && 
     string.Equals(ot.Name, this.Name, StringComparison.OrdinalIgnoreCase); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int result = this.ID.GetHashCode(); 
      result = (result * 397)^this.Name.GetSafeHashCode(); 
      return result; 
     } 
    } 
} 

的代碼我使用比較集合和獲得差異是隻是一個簡單的使用PLinq的Linq查詢。

ParallelQuery p1Coll = sourceColl.AsParallel(); 
ParallelQuery p2Coll = destColl.AsParallel(); 

List<object> diffs = p2Coll.Where(r => !p1Coll.Any(m => m.Equals(r))).ToList(); 

有沒有人知道比較這許多對象的更快的方法?目前在四核電腦上需要約40秒+/- 2秒。根據數據做一些分組然後再比較每組數據可能會更快嗎?如果我先根據名稱對數據進行分組,那麼最終會得到大約490個獨特的對象,如果我先用ID對它進行分組,那麼最終會得到大約622個獨特的對象。

+0

在開始之前,請考慮緩存哈希碼。每次計算它都會損失一些時間。 –

+0

什麼是'Name.GetSafeHashCode()'?也許緩存你的HashCode以免重新計算可能會有幫助,但我不知道有多少(如果/當'ID'或'Name'發生變化,你還必須無效/重新計算它) –

+0

我想,你必須避免LINQ來實現性能。如果你能訂購你的收藏品,這將是最好的一點。 –

回答

15

您可以使用Except方法,它會爲您提供p2Coll中不在p1Coll中的所有項目。

var diff = p2Coll.Except(p1Coll); 

UPDATE(一些性能測試):

免責聲明:

實際使用時間取決於多種因素(如集合的內容,硬件,什麼是你的機器上運行,散列碼衝突的數量等),這就是爲什麼我們有複雜性和Big O表示法(請參閱DanielBrückner評論)。

這裏是我4歲的計算機上運行10次一些性能統計:

Median time for Any(): 6973,97658ms 
Median time for Except(): 9,23025ms 

Source code爲我的測試是可在依據。


更新2:

如果你想擁有不同於第一和第二收集不同的項目,你必須真正做既ExpectUnion結果:

var diff = p2Coll.Except(p1Coll).Union(p1Coll.Except(p2Coll)); 
+0

真的,速度更快嗎?你測試了嗎? –

+8

這應該會快很多 - 問題的解決方案是'O(m * n)',這個解決方案在內部建立一個散列表,因此是'O(m + n)'。 –

+0

添加了一個髒快速測試... –

0

Intersect

int[] id1 = { 44, 26, 92, 30, 71, 38 }; 
int[] id2 = { 39, 59, 83, 47, 26, 4, 30 }; 

IEnumerable<int> both = id1.Intersect(id2); 

foreach (int id in both) 
    Console.WriteLine(id); 

/* 
This code produces the following output: 

26 
30 
*/ 
+0

以上答案比較好。 –

+1

但'Intersect'則相反。他正在尋找解決分歧的方法。 –

+0

但是'除外'也不是差異(除非第二組保證是第一組的子集)。然而,問題中給出的代碼是計算的。 –