我有一个对象,我想用它来查找其他对象。我将使用Dictionary<TKey, TValue>()
。
关键对象有两个唯一标识它的字符串,比如KeyObj.Str1
和KeyObj.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将是最简单的,但似乎根据参考值索引字典效率低下。
如果密钥对象包含一个唯一的字符串,那么显而易见的选择就是使用它,但是只有两个字符串组合起来才是唯一的,这使得它变得更加困难。
答案 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