简体   繁体   English

Hashtable / Dictionary但是键由多个值组成?

[英]Hashtable/Dictionary but with key composed of multiple values?

Lets say I have an object that has stringProp1, stringProp2. 假设我有一个具有stringProp1,stringProp2的对象。 I wish to store each combination of stringProp1, stringProp2 in a Dictionary. 我希望将stringProp1,stringProp2的每个组合存储在Dictionary中。 Initially I was storing the key as key = stringProp1+stringProp2 but this can actually cause a bug depending on the 2 values. 最初我将密钥存储为key = stringProp1 + stringProp2,但实际上这可能会导致错误,具体取决于2个值。 Is the best solution for this problem to create a custom dictionary class or is there a better way using built-in .NET classes? 这个问题的最佳解决方案是创建自定义字典类还是使用内置.NET类有更好的方法?

In .NET 4, you can use a System.Tuple as a key. 在.NET 4中,您可以使用System.Tuple作为键。

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

Why not just use a struct with 2 strings as a key? 为什么不直接使用带有2个字符串的结构? This would be the simplest. 这将是最简单的。

It does not matter what data structure you use as the key as long as the key holds the necessary information for a comparer to properly compare/hash. 只要密钥包含比较器正确比较/散列的必要信息,您使用什么数据结构作为密钥并不重要。

You can even use your objects as keys in the dictionary and compare on any field you like with an appropriate EqualityComparer implementation. 您甚至可以将对象用作字典中的键,并使用适当的EqualityComparer实现在您喜欢的任何字段上进行比较。 This one compares on two string properties using ordinal comparison: 这个使用序数比较比较两个字符串属性:

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);
}

You can search for an object by creating a dummy one, filling in the string keys and using the dummy as the key for the lookup. 您可以通过创建虚拟对象,填充字符串键并使用虚拟对象作为查找键来搜索对象。 If you do not like this idea, or it is not feasible, just do as @Vlad said and extract the keys in a struct or class. 如果你不喜欢这个想法,或者它不可行,那就像@Vlad那样说并在结构或类中提取密钥。 In this case, modify the comparer to derive from EqualityComparer<MyKeyStructOrClass> . 在这种情况下,修改比较器以从EqualityComparer<MyKeyStructOrClass>派生。

Note that I've used Jon Skeet's method for combining string hashes. 请注意,我使用了Jon Skeet的方法来组合字符串哈希。 It might be better than the XOR method found on MSDN . 它可能比MSDN上XOR方法更好。 If you feel that it is steel inadequate, feel free to treat the strings with another hash implementation - Hsieh , Murmur , Bob Jenkin's , or whatever you believe in. Here is a nice page about hash functions that actually has some C# code as well. 如果你觉得它不合适,可以随意用另一个哈希实现来处理字符串 - 谢谢MurmurBob Jenkin ,或者你信任的任何东西。这里有一个很好的关于散列函数的页面 ,它实际上也有一些C#代码。

Depending on how you populate the dictionary and what you do with it, it's possible to use an anonymous type as the key. 根据您填充字典的方式以及使用它执行的操作,可以使用匿名类型作为键。 For example if you have a class Person : 例如,如果您有一个Person类:

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

And if you had a sequence of these, an IEnumerable<Person> , and wanted to create a dictionary that maps names to ages, you can write: 如果您有一个这样的序列,一个IEnumerable<Person> ,并且想要创建一个将名称映射到年龄的字典,您可以编写:

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

This gives you a dictionary with the first name and last name as the key, and stores the entire Person as the value. 这将为您提供一个以名字和姓氏为键的字典,并将整个Person存储为值。 You can later look up a key with: 您可以稍后通过以下方式查找密钥:

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

This won't help help you much if you're trying to pass the dictionary between different classes or even methods, it becomes hard to manage, but for doing some quick data processing in a single method, it works great. 如果你试图在不同的类甚至方法之间传递字典,这对你没有多大帮助,它变得难以管理,但是为了在单个方法中进行一些快速数据处理,它工作得很好。 In fact, it's quite common to use anonymous classes as the key for the GroupBy extension method or the group by query comprehension syntax. 事实上,使用匿名类作为GroupBy扩展方法的键或group by查询理解语法的group by是很常见的。

You can put a delimiter in there, if there is a character that won't turn up in either string. 如果有一个字符在两个字符串中都没有出现,你可以在其中放置一个分隔符。

eg 例如

stringProp1 + "|" + stringProp2

If there isn't then I'd recommend Dictionary<string, Dictionary<string, MyValueType>> as in 如果没有,那么我建议使用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;

You can use the MD5 algorithm to produce a value for each string and then sum up the two values. 您可以使用MD5算法为每个字符串生成一个值,然后将这两个值相加。 The result is the key. 结果是关键。
.NET provide the class MD5CryptoServiceProvider in the System.Security.Cryptography namespace. .NET在System.Security.Cryptography命名空间中提供类MD5CryptoServiceProvider。 That class contains the method ComputeHash to compute the hash value. 该类包含ComputeHash方法来计算哈希值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM