2010-03-02 77 views
3

可以說我有一個對象,它有stringProp1,stringProp2。我希望將stringProp1,stringProp2的每個組合存儲在Dictionary中。最初,我將密鑰存儲爲key = stringProp1 + stringProp2,但實際上這可能會導致一個錯誤,具體取決於2個值。對於這個問題來說,創建自定義字典類還是有更好的方式使用內置的.NET類是最好的解決方案嗎?散列表/字典,但鍵與多個值組成?

回答

1

這不要緊,你的關鍵,只要鑰匙適用於一個比較器,以正確比較/哈希必要的信息,使用什麼數據結構。

您甚至可以將您的對象用作字典中的鍵,並將您喜歡的任何字段與適當的EqualityComparer實現進行比較。這其中用序號比較兩個String屬性比較了:

class MyObject 
{ 
    public string StringProp1 { get; set; } 
    public string StringProp2 { get; set; } 
    public MyObject(string prop1, string prop2) 
    { 
     StringProp1 = prop1; 
     StringProp2 = prop2; 
    } 
} 

class MyObjectComparerS1S2 : EqualityComparer<MyObject> 
{ 
    //Change this if you need e.g. case insensitivity or 
    //culture-specific comparisons 
    static StringComparer comparer = StringComparer.Ordinal; 

    public override bool Equals(MyObject x, MyObject y) 
    { 
     return 
      comparer.Equals(x.StringProp1, y.StringProp1) && 
      comparer.Equals(x.StringProp2, y.StringProp2); 
    } 

    public override int GetHashCode(MyObject obj) 
    { 
     //Uncomment this if running in a checked context 
     //Copycat of Jon Skeet's string hash combining 
     //unchecked 
     //{ 
      return 
       (527 + comparer.GetHashCode(obj.StringProp1)) * 31 + 
       comparer.GetHashCode(obj.StringProp2); 
     //} 
    } 

    public static readonly MyObjectComparerS1S2 Instance = 
     new MyObjectComparerS1S2(); 

} 

static void Main(string[] args) 
{ 
    Dictionary<MyObject, MyObject> dict = 
     new Dictionary<MyObject, MyObject>(MyObjectComparerS1S2.Instance); 
    MyObject obj = new MyObject("apple", "plum"); 
    dict.Add(obj, obj); 
    MyObject search = new MyObject("apple", "plum"); 
    MyObject result = dict[search]; 
    Console.WriteLine("{0}:{1}", result.StringProp1, result.StringProp2); 
} 

可以通過創建虛擬之一,在字符串鍵填充和使用虛擬作爲查找密鑰搜索對象。 如果你不喜歡這個想法,或者這是不可行的,只要按照@Vlad的說法提取結構或類中的鍵即可。在這種情況下,修改比較器以從EqualityComparer<MyKeyStructOrClass>派生。

請注意,我用Jon Skeet's method來組合字符串散列。這可能比XOR method found on MSDN更好。如果你覺得它是鋼鐵不足的話,可以隨意用另一個散列實現來對待字符串 - Hsieh,Murmur,Bob Jenkin's,或者你認爲的任何東西。下面是一個nice page about hash functions,它實際上也有一些C#代碼。

0

如果有一個字符不會出現在任何一個字符串中,您可以在其中放置一個分隔符。

stringProp1 + "|" + stringProp2 

如果沒有,那麼我建議Dictionary<string, Dictionary<string, MyValueType>>

var dictionary = new Dictionary<string, Dictionary<string, MyValueType>>(); 
// .... Do stuff 
if (!dictionary.ContainsKey(stringProp1)) 
    dictionary.Add(stringProp1, new Dictionary<string, MyValueType>()); 
dictionary[stringProp1][stringProp2] = myValue; 
+0

這不起作用。 「blah |」,「blah」和「blah」,「| blah」這對組合如何?你需要小心。 – Keltex 2010-03-02 21:14:03

0

可以使用MD5算法來產生一個值爲每個字符串,然後總結兩個值。結果是關鍵。
.NET在System.Security.Cryptography命名空間中提供類MD5CryptoServiceProvider。該類包含ComputeHash方法來計算散列值。

+0

這不可靠。如果字符串是隨機的,則1/2^128的概率是md5散列將會發生衝突。這將會非常緩慢。 – Vlad 2010-03-02 21:28:11

1

爲什麼不只是使用一個結構與2個字符串作爲關鍵?這將是最簡單的。

3

在.NET 4中,您可以使用System.Tuple作爲關鍵。

var dict = new Dictionary<Tuple<string,string>, int>(); 
dict.Add(Tuple.Create("foo","bar"), 1); 
+0

如果你想在早期版本的.NET中使用它,你也可以引用FSharp.Core。 – 2010-03-05 01:14:50

+0

你也可以使用.Net 3.5中的keyvaluepair作爲新的字典>。但看起來很醜。 – Biswanath 2010-03-21 20:38:18

1

根據填充詞典的方式以及使用它的方式,可以使用匿名類型作爲鍵。例如,如果你有一個類Person

public class Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public int Age { get; set; } 
} 

如果你有這些的IEnumerable<Person>序列,並希望創建一個映射名年齡字典,你可以寫:

var personDictionary = people.ToDictionary(p => new { p.FirstName, p.LastName }); 

這會爲您提供一個名字和姓氏爲字典的字典,並將整個Person作爲值存儲。您可以在以後查找用鑰匙:

personDictionary.TryGetValue(new { FirstName = "John", LastName = "Smith" }, 
    out person); 

這不會有助於幫助你多,如果你想通過不同的課程或甚至方法之間的字典,它變得難以管理,但做一些以單一方法快速處理數據,效果很好。事實上,使用匿名類作爲GroupBy擴展方法或group by查詢理解語法的關鍵字很常見。

相關問題