我需要一个字节数组的HashSet来检查集合中是否存在给定的字节数组。但似乎这对字节数组(或任何数组)都不起作用。
这是我的测试代码:
void test()
{
byte[] b1 = new byte[] { 1, 2, 3 };
byte[] b2 = new byte[] { 1, 2, 3 };
HashSet<byte[]> set = new HashSet<byte[]>();
set.Add(b1);
set.Add(b2);
Text = set.Count.ToString();//returns 2 instead of the expected 1.
}
有没有办法为字节数组创建一个HashSet?
答案 0 :(得分:2)
使用HashSet
构建IEqualityComparer<byte[]>
。你不想在这里使用界面。虽然byte[]
实际上实现了IEnumerable<byte>
,IList<byte>
等接口,但由于涉及重量,使用它们是一个坏主意。你没有使用string
实施IEnumerable<char>
的事实,所以不要byte[]
。
public class bytearraycomparer : IEqualityComparer<byte[]> {
public bool Equals(byte[] a, byte[] b)
{
if (a.Length != b.Length) return false;
for (int i = 0; i < a.Length; i++)
if (a[i] != b[i]) return false;
return true;
}
public int GetHashCode(byte[] a)
{
uint b = 0;
for (int i = 0; i < a.length; i++)
b = ((b << 23) | (b >> 9)) ^ a[i];
return unchecked((int)b);
}
}
void test()
{
byte[] b1 = new byte[] { 1, 2, 3 };
byte[] b2 = new byte[] { 1, 2, 3 };
HashSet<byte[]> set = new HashSet<byte[]>(new bytearraycomparer );
set.Add(b1);
set.Add(b2);
Text = set.Count.ToString();
}
https://msdn.microsoft.com/en-us/library/bb359100(v=vs.110).aspx
如果您要在建议的重复问题中使用答案,则最终会进行一次函数调用,并且每个字节处理一次数组边界检查。你不想要那个。如果以最简单的方式表示,则抖动将内联提取,然后注意边界检查不会失败(数组不能调整大小)并省略它们。只有一个函数调用整个数组。耶。
与字节数组相比,列表往往只有少数元素,因此常常是简单的哈希函数,如foreach (var item in list) hashcode = hashcode * 5 + item.GetHashCode()
;如果你对字节数组使用那种哈希函数,你会遇到问题。乘以一个小的奇数技巧最终会变得相当偏倚,以至于舒适。我在这里给出的特定哈希函数可能不是最优的,但是我们已经对这个系列进行了测试,并且它在三百万个条目中运行良好。由于拥有大量只有两个字节长/不同的冲突,乘法很快就陷入了麻烦。如果你避免使用简并数,这个系列就不会在两个字节中发生冲突,而且大多数都没有三个字节的冲突。
考虑实际使用情况:到目前为止,这里最常见的两件事是字节字符串,并检查实际文件的相同性。在任何一种情况下,获取前几个字节的哈希码很可能是个坏主意。 String
的哈希码使用整个字符串,因此字节字符串应该相同,并且大多数重复的文件在前几个字节中没有唯一的前缀。对于N个条目,如果N上的平方根有哈希冲突,那么在生成哈希码时你也可能已经遍历了整个数组,忽略了比较比哈希更慢的事实。