在这里讨论了SO之后,我已经多次读过可变结构是"邪恶"的评论(就像这个问题的答案一样).
C#中可变性和结构的实际问题是什么?
很久以前,我以1.25美元的价格从交易台上买了一本数据结构书.在其中,哈希函数的解释说,由于"数学的本质",它最终应该由质数修改.
你对1.25美元的书有什么期望?
无论如何,我有多年的时间来思考数学的本质,但仍然无法弄明白.
当存在大量的桶时,数字的分布是否真的更均匀?或者这是一个老程序员的故事,每个人都接受,因为其他人都接受它?
我们如何决定hashCode()集合方法的最佳实现(假设equals方法已被正确覆盖)?
我想比较两个集合(在C#中),但我不确定有效实现它的最佳方法.
我已经阅读了关于Enumerable.SequenceEqual的其他帖子,但这并不是我正在寻找的.
在我的情况下,如果它们都包含相同的项目(无论顺序),则两个集合将是相等的.
例:
collection1 = {1, 2, 3, 4};
collection2 = {2, 4, 1, 3};
collection1 == collection2; // true
Run Code Online (Sandbox Code Playgroud)
我通常做的是遍历一个集合中的每个项目,看看它是否存在于另一个集合中,然后循环遍历另一个集合的每个项目,看它是否存在于第一个集合中.(我首先比较长度).
if (collection1.Count != collection2.Count)
return false; // the collections are not equal
foreach (Item item in collection1)
{
if (!collection2.Contains(item))
return false; // the collections are not equal
}
foreach (Item item in collection2)
{
if (!collection1.Contains(item))
return false; // the collections are not equal
}
return true; // the collections are equal
Run Code Online (Sandbox Code Playgroud)
但是,这并不完全正确,并且它可能不是比较两个集合的最有效方法.
我能想到的一个例子是错误的:
collection1 …Run Code Online (Sandbox Code Playgroud) 所以我有一组对象.确切的类型并不重要.从中我想提取一对特定属性的所有唯一对,因此:
myObjectCollection.Select(item=>new
{
Alpha = item.propOne,
Bravo = item.propTwo
}
).Distinct();
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:在这种情况下会不会使用默认对象equals(这对我来说没用,因为每个对象都是新的)或者可以告诉它做一个不同的equals(在这种情况下,Alpha和Bravo的值相等) =>相等的实例)?有没有办法实现这个结果,如果不这样做的话?
假设您有两个哈希H(A)并且H(B)您想要将它们组合在一起.我已经读到了将两个哈希值组合在一起的好方法XOR,例如XOR( H(A), H(B) ).
我发现的最佳解释在这里简要介绍了这些哈希函数指南:
对具有大致随机分布的两个数字进行异或,导致另一个数字仍具有大致随机分布*,但现在取决于这两个值.
...
*在两个数字相结合的每个比特,一个输出0,如果两个比特相等,否则为1.换句话说,在组合的50%,1将输出.因此,如果两个输入位各有大约50-50的机会为0或1,那么输出位也是如此.
你能解释为什么XOR应该是组合散列函数(而不是OR或AND等)的默认操作的直觉和/或数学吗?
鉴于像System.Collections.Generic.HashSet<>accept 这样的集合null成为集合成员,可以询问哈希代码null应该是什么.它看起来像框架使用0:
// nullable struct type
int? i = null;
i.GetHashCode(); // gives 0
EqualityComparer<int?>.Default.GetHashCode(i); // gives 0
// class type
CultureInfo c = null;
EqualityComparer<CultureInfo>.Default.GetHashCode(c); // gives 0
Run Code Online (Sandbox Code Playgroud)
对于可以为空的枚举,这可能会(有点)出现问题.如果我们定义
enum Season
{
Spring,
Summer,
Autumn,
Winter,
}
Run Code Online (Sandbox Code Playgroud)
然后Nullable<Season>(也称为Season?)可以只取五个值,但其中两个,即null和Season.Spring,具有相同的哈希码.
写这样一个"更好"的平等比较器是很诱人的:
class NewNullEnumEqComp<T> : EqualityComparer<T?> where T : struct
{
public override bool Equals(T? x, T? y)
{
return Default.Equals(x, y);
}
public override int …Run Code Online (Sandbox Code Playgroud) 正如标题所说:我是否需要覆盖==运营商?怎么样的.Equals()方法?我缺少什么?
我在C#中有一个结构:
public struct UserInfo
{
public string str1
{
get;
set;
}
public string str2
{
get;
set;
}
}
Run Code Online (Sandbox Code Playgroud)
唯一的规则是 UserInfo(str1="AA", str2="BB").Equals(UserInfo(str1="BB", str2="AA"))
如何覆盖此结构的GetHashCode函数?
Eclipse 3.5有一个非常好的功能来生成Java hashCode()函数.它会产生例如(稍微缩短:)
class HashTest {
int i;
int j;
public int hashCode() {
final int prime = 31;
int result = prime + i;
result = prime * result + j;
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
(如果类中有更多属性,result = prime * result + attribute.hashCode();则对每个附加属性重复.对于int.可以省略.hashCode().)
这似乎很好,但选择31为素数.它可能来自Java String的hashCode实现,它被用于性能原因,这些原因在引入硬件乘法器之后很久就消失了.对于i和j的小值,这里有许多哈希码冲突:例如(0,0)和(-1,31)具有相同的值.我认为这是一个Bad Thing(TM),因为经常出现小值.对于String.hashCode,您还会发现许多具有相同哈希码的短字符串,例如"Ca"和"DB".如果选择大素数,如果选择素数,此问题就会消失.
所以我的问题是:选择什么是好的素数?你用什么标准来找到它?
这是一个普遍的问题 - 所以我不想给i和j一个范围.但我认为在大多数应用中,相对较小的值比较大的值更常出现.(如果你有大的值,素数的选择可能不重要.)它可能没有多大区别,但更好的选择是一种简单明了的方法来改善这一点 - 那么为什么不这样做呢?Commons lang HashCodeBuilder也提出了奇怪的小值.
(澄清:这不是重复为什么String中的Java的hashCode()使用31作为乘数?因为我的问题不关心JDK中31的历史,而是关于新代码中更好的值使用相同的基本模板.没有任何答案试图回答.)
c# ×5
hash ×4
.net ×3
equality ×2
hashcode ×2
java ×2
struct ×2
collections ×1
comparison ×1
cryptography ×1
distinct ×1
equals ×1
hashtable ×1
immutability ×1
linq ×1
mutable ×1
null ×1
operators ×1
primes ×1
probability ×1
xor ×1