2010-03-02 66 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查询理解语法的关键字很常见。

相关问题