我有兩個字符串,該ID喜歡用它們作爲字典的鍵,但即時通訊有點懶創建另一個對象,計算串等的哈希碼兩個字符串的字典重點
所以不是說,我可以得到兩個字符串的hashcode,添加它們並使用結果作爲Dictionary的關鍵字?
有可能導致碰撞?對?。
任何想法?
我有兩個字符串,該ID喜歡用它們作爲字典的鍵,但即時通訊有點懶創建另一個對象,計算串等的哈希碼兩個字符串的字典重點
所以不是說,我可以得到兩個字符串的hashcode,添加它們並使用結果作爲Dictionary的關鍵字?
有可能導致碰撞?對?。
任何想法?
我有兩個字符串,如以 該ID使用它們作爲字典鍵,但即時通訊 有點懶創建另一個對象
在.NET 4.0中,你可以使用Tuple<T1, T2>
類作爲鍵,T1和T2 =字符串。
我可以得到兩個字符串 的散列碼,添加它們並使用結果作爲詞典的 關鍵?
公式Tuple<T1, T2>
用來組合哈希碼是一樣的東西(不記錄或保證不變):((h1 << 5) + h1)^h2
,這應該是足夠體面的你的目的。順便說一句,天真添加通常不是組合散列碼的最佳方式。
有可能造成碰撞? 對不對?
這總是可能的,即使是單個字符串。有比32位整數更多的字符串。
使用一個元組:
var dict = new Dictionary<Tuple<string,string>,SomeType>();
dict.Add(Tuple.Create("Hello","World"), new SomeType());
如果你在.NET 4中,你可以使用Tuple類:
Dictionary<Tuple<string, string>, TValue> dict = new ...
如果你不是在.NET 4中,需要創建你自己的類型來保存這個。
您可以使用KeyValuePair結構,但它繼承了基本值類型的相關方法,因此嚴重依賴於反射。這會對性能產生影響(見答案的底部。)
鍵值對:
Dictionary<KeyValuePair<string, string>, TValue> dict = new ...
這裏的一般類型,你可以使用,如果你不想做飯了自己:
public struct SimpleTuple<TValue1, TValue2>
{
private readonly TValue1 _Value1;
private readonly TValue2 _Value2;
public SimpleTuple(TValue1 value1, TValue2 value2)
{
_Value1 = value1;
_Value2 = value2;
}
public TValue1 Value1 { get { return _Value1; } }
public TValue2 Value2 { get { return _Value2; } }
public int GetHashCode()
{
unchecked
{
int result = 37;
result *= 23;
if Value1 != null)
result += Value1.GetHashCode();
result *= 23;
if (Value2 != null)
result += Value2.GetHashCode();
return result;
}
}
public override bool Equals(object obj)
{
if (obj == null) return false;
if (obj.GetType() != typeof(SimpleTuple<TValue1, TValue2>))
return false;
var other = (SimpleTuple<TValue1, TValue2>)obj;
return Equals(other.Value1, Value1) && Equals(other.Value2, Value2);
}
}
當然,KeyValuePair也適用於.NET 4.0,正如
好
不好。
至於碰撞,這取決於你的意思。散列表(字典在內部使用散列表結構)始終有可能發生關鍵衝突,但這就是比較起作用的地方。如果兩個不同的鍵生成相同的哈希碼,則字典類將比較鍵與鍵以查看它們是否真的是相同的值,或者只是生成相同的哈希碼。
背後,爲什麼一個哈希表總會有衝突的可能性的推理是最好用pidgeonhole principle (Wikipedia)描述。
這意味着,如果兩個不同的密鑰會引起衝突,它不會是一個問題,他們都會被保存,用正確的價值觀,在字典中。
當然,如果您創建兩次相同的密鑰,字典會將其計爲同一個密鑰,並且無法添加新值或覆蓋現有密鑰(具體取決於您如何添加該值。 )
這將在重複鍵拋出一個異常:
dict.Add(key, value);
這將增加,或覆蓋現有:
dict[key] = value;
在迴應阿尼的評論,我寫了下面簡單的測試腳本LINQPad。輸出是:
KeyValuePair: 975ms MyKeyValuePair: 52ms
腳本:
void Main()
{
const int iterations = 10 * 1000 * 1000;
// JIT preheat
Test1(1);
Test2(1);
Stopwatch sw = Stopwatch.StartNew();
Test1(iterations);
sw.Stop();
Debug.WriteLine("KeyValuePair: " + sw.ElapsedMilliseconds + "ms");
sw = Stopwatch.StartNew();
Test2(iterations);
sw.Stop();
Debug.WriteLine("MyKeyValuePair: " + sw.ElapsedMilliseconds + "ms");
}
public static void Test1(int iterations)
{
for (int index = 0; index < iterations; index++)
{
var kvp = new KeyValuePair<int, int>(index, index);
kvp.GetHashCode();
}
}
public static void Test2(int iterations)
{
for (int index = 0; index < iterations; index++)
{
var kvp = new MyKeyValuePair<int, int>(index, index);
kvp.GetHashCode();
}
}
public struct MyKeyValuePair<TKey, TValue>
{
private readonly TKey _Key;
private readonly TValue _Value;
public MyKeyValuePair(TKey key, TValue value)
{
_Key = key;
_Value = value;
}
public TKey Key { get { return _Key; } }
public TValue Value { get { return _Value; } }
public int GetHashCode()
{
unchecked
{
int result = 37;
result *= 23;
if (Key != null)
result += Key.GetHashCode();
result *= 23;
if (Value != null)
result += Value.GetHashCode();
return result;
}
}
public override bool Equals(object obj)
{
if (obj == null) return false;
if (obj.GetType() != typeof(MyKeyValuePair<TKey, TValue>))
return false;
var other = (MyKeyValuePair<TKey, TValue>)obj;
return Equals(other.Key, Key) && Equals(other.Value, Value);
}
}
使用KVPs作爲關鍵的經驗?我想知道性能會是什麼樣子,考慮到等同性和散列碼計算應該來自'System.ValueType',因爲它似乎並沒有覆蓋它們。 – Ani
我沒有直接衡量這一點,但我從來沒有在字典是性能分析過程中的主要罪魁禍首的位置。它可能比用特定方法手動編碼類似的類型慢得多。讓我這樣做,然後回來編輯。 –
@Ani,你現在在看,KeyValuePair是一個不錯的選擇。我會編輯我的答案。 –
簡單的解決方案,以及一個與.NET的所有版本。只需將字符串連接在一起即可。
var dictionary = new Dictionary<string, int>();
dictionary.Add("The meaning" + " of life, the universe, and everything", 42);
當然,這僅與2串工作(儘管你可以在許多其他類型使用的ToString()),如果你不需要僅由兩個字符串中的一個來查找字典,但如果你有兩個很簡單。
我會補充說,如果有兩個字符串中沒有包含某些字符,這種技術就可以工作。例如姓名和姓氏。他們都不應該有\ n(新行)。所以名稱\ nSurname是「足夠好」(注意,一些狡猾的黑客可以使用它來破解你的網站!這將是非常困難的,但不是不可能的)。考慮到許多系統都是基於C的,可能字符\ 0使用起來相當安全。 (或者你可以簡單地逃脫你使用分割字符串,例如字符的任何occurrance:Name.Replace(「|」,「||」)+「|」 +姓 – xanatos
哪個.NET版本,你有嗎? –