2016-04-03 22 views
1

我試圖在C#中使用int數組作爲鍵,並且我看到的行爲是意外的(對於我)。如何使用基本列表或列表作爲C#中的字典的關鍵字

var result = new Dictionary<int[], int>(); 
result[new [] {1, 1}] = 100; 
result[new [] {1, 1}] = 200; 

Assert.AreEqual(1, result.Count); // false is 2 

它似乎也與列表一樣。

var result = new Dictionary<List<int>, int>(); 
result[new List<int> { 1, 1 }] = 100; 
result[new List<int> { 1, 1 }] = 200; 

Assert.AreEqual(1, result.Count); // false is 2 

我期待Dictionary能夠使用Equals來決定Key是否存在於地圖中。這似乎並非如此。

有人可以解釋爲什麼以及如何讓這種行爲起作用嗎?

+2

默認相等是數組/列表本身的實例相等,而不是數據結構的內容。你傳遞了兩個不同的實例,它們的內容相同,不會導致關鍵衝突。在構建字典時,您可以傳遞自己的'IEqualityComperer',該字典可以使用任何您想要比較鍵的邏輯來實現相等性。 –

回答

5

.NET列表和數組沒有內置的相等比較,所以你需要提供自己:

class ArrayEqComparer : IEqualityComparer<int[]> { 

    public static readonly IEqualityComparer<int[]> Instance = 
     new ArrayEqComparer(); 

    public bool Equals(int[] b1, int[] b2) { 
     if (b2 == null && b1 == null) 
      return true; 
     else if (b1 == null | b2 == null) 
      return false; 
     return b1.SequenceEqual(b2); 
    } 

    public int GetHashCode(int[] a) { 
     return a.Aggregate(37, (p, v) => 31*v + p); 
    } 
} 

現在你可以構建你的字典如下:

var result = new Dictionary<int[],int>(ArrayEqComparer.Instance); 
+0

有這種行爲的內置字典嗎?或在流行的圖書館? – joejag

+0

@joejag讓我驚訝的是,雖然框架有足夠的「管道」來使其一般工作,但沒有內置的集合比較器。我也不知道任何流行的庫提供這種功能。 – dasblinkenlight

+0

出於好奇,爲什麼你的'GetHasCode'中的37和31? – devuxer

0

您正在通過對象(數組或列表)作爲關鍵。作爲一個新的對象它有一個不同的引用,因此它被接受爲新的密鑰。

1

Dictionary類允許自定義相等比較器作爲字典比較器。通過使用Linq.Enumerable.SequenceEquals返回所有列表元素(0^first^second ...)和Equals(IList x,IList y)的xor(^運算符),提供GetHashCode(IList obj)來實現IEqualityComparer> 。然後將它的一個實例傳遞給Dictionary構造函數。