选择一个好的字典键

时间:2009-03-20 15:56:44

标签: c# .net dictionary indexing key

我有一个对象,我想用它来查找其他对象。我将使用Dictionary<TKey, TValue>()

关键对象有两个唯一标识它的字符串,比如KeyObj.Str1KeyObj.Str2

您建议我使用什么作为字典的关键字?

1:字符串的串联。

Dictionary<String, TValue>();
Key = KeyObj.Str1:KeyObj.Str2; ("somestring:anotherstring")

2:每个对象识别它的唯一整数?

Dictionary<int, TValue>();
KeyObj.ID = _nextID++;
Key = KeyObj.ID;

3:对象的引用。

Dictionary<KeyObj, TValue>();
Key = KeyObj;

选项3将是最简单的,但似乎根据参考值索引字典效率低下。

如果密钥对象包含一个唯一的字符串,那么显而易见的选择就是使用它,但是只有两个字符串组合起来才是唯一的,这使得它变得更加困难。

9 个答案:

答案 0 :(得分:2)

连接字符串应该效果最好。

如果您知道他们的组合是唯一的,那么您应该选择 - 请记住Hash代码通常唯一,但并非总是如此。

答案 1 :(得分:2)

如果你可以适当地覆盖GetHashCode()和Equals(),你可以使用选项3,例如:

    public override int GetHashCode()
    {
        return str1.GetHashCode() ^ str2.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        if (!obj is KeyObj)
        {
            return false;
        }

        KeyObj key = (KeyObj)obj;
        return this.str1.Equals(key.str1) && this.str2.Equals(key.str2);
    }

答案 2 :(得分:1)

连接它们可能是最好的主意。您可以在执行连接的KeyObj对象中公开属性,这样您就不必在每次访问字典值时都执行该属性。

修改

我显然误解了这个问题。我认为你真正想做的是1和3的混合,你可以覆盖Equals()GetHashCode()来使用唯一标识对象的string(只需确保它们是不可变!)

public override Equals(object obj) 
{
   if (obj == null || !(obj is KeyObj))
      return false;
   KeyObj other = (KeyObj)obj;
   if (this.Key1 == other.Key1 && this.Key2 == other.Key2)
     return true;
   return false;
}

public override GetHashCode()
{
    return (this.Key1 + this.Key2).GetHashCode();
}

然后你可以使用你建议的第三个选项:

Dictionary<KeyObj, ValueObj>...

答案 3 :(得分:1)

使用KeyObj.GetHashCode()?

答案 4 :(得分:1)

它们中的任何一个都是有效的,但我假设您希望能够根据两个字符串之一快速找到这些对象,因此使用int作为键意味着您仍然需要扫描找到你想要的对象的值。

字符串是唯一的,还是仅在组合时?如果它们都是独一无二的,并且您愿意交换一些空间,那么您可以这样做:

dict.Add(KeyObj.Str1, KeyObj);
dict.Add(KeyObj.Str2, KeyObj);

并且使用每个唯一字符串作为键,对字典中的对象进行两次引用。或者,如果它们只是唯一的,那么你总是可以组合它们,并且它将在内部使用哈希码来查找它们。

答案 5 :(得分:0)

您不需要使用新类作为字典键。使用一个新的结构,因为它将更轻量级......并且它显然包含这两个字符串值。

答案 6 :(得分:0)

如果性能是主要考虑因素,您可以考虑使用两个字符串的哈希值。但是,你的'价值'字段必须包含键和值。

我提到另一个SO问题,我只需要找到它。

Is it faster to search for a large string in a DB by its hashcode?

但是这个问题更多的是面向数据库。并且性能被考虑用于数千次迭代。

答案 7 :(得分:0)

请记住,字典是一个美化的哈希表,所以密钥(没有双关语)是使用一个密钥,这个密钥会导致与另一个密钥发生很少(如果有的话)冲突。我倾向于#3,但这是假设KeyObj类型有一个很好的哈希值生成器。

答案 8 :(得分:0)

字符串作为键是最好的,请参阅我的测试代码:

var tupleKeyDict = new Dictionary,string&gt;();

        for (int i = 0; i < 1000000; i++)
        {
            tupleKeyDict.Add(new Tuple<int, int>(i,0),i.ToString() );
        }

        System.Diagnostics.Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();
        string e1 = tupleKeyDict[new Tuple<int, int>(0, 0)];
        string e2 = tupleKeyDict[new Tuple<int, int>(500000, 0)];
        string e3 = tupleKeyDict[new Tuple<int, int>(999999, 0)];
        stopWatch.Stop();
        Console.WriteLine("Tuplekey cost(tick): " + stopWatch.ElapsedTicks.ToString());
        Console.WriteLine("Tuplekey cost(ms): " + stopWatch.ElapsedMilliseconds.ToString());





        var strKeyDict = new Dictionary<string, string>();

        for (int i = 0; i < 1000000; i++)
        {
            strKeyDict.Add(i.ToString() + ":0", i.ToString());
        }

        System.Diagnostics.Stopwatch stopWatch2 = new Stopwatch();
        stopWatch2.Start();
        string se1 = strKeyDict["0:0"];
        string se2 = strKeyDict["500000:0"];
        string se3 = strKeyDict["999999:0"];
        stopWatch2.Stop();
        Console.WriteLine("strkey cost(tick): " + stopWatch2.ElapsedTicks.ToString());
        Console.WriteLine("strkey cost(ms): " + stopWatch2.ElapsedMilliseconds.ToString());




        var intKeyDict = new Dictionary<int, string>();

        for (int i = 0; i < 1000000; i++)
        {
            intKeyDict.Add(i, i.ToString());
        }

        System.Diagnostics.Stopwatch stopWatch3 = new Stopwatch();
        stopWatch3.Start();
        string ie1 = intKeyDict[0];
        string ie2 = intKeyDict[500000];
        string ie3 = intKeyDict[999999];
        stopWatch3.Stop();
        Console.WriteLine("intkey cost(tick): " + stopWatch3.ElapsedTicks.ToString());
        Console.WriteLine("intkey cost(ms): " + stopWatch3.ElapsedMilliseconds.ToString());

输出: Tuplekey成本(刻度):104 Tuplekey成本(ms):0 strkey cost(tick):12 strkey cost(ms):0 intkey cost(tick):66 intkey cost(ms):0