【问题标题】:Structural hashing of array of double in c#c#中double数组的结构散列
【发布时间】:2013-03-07 13:20:26
【问题描述】:

我想在 C# 数组中进行结构散列,但我不知道该怎么做。 在任何语言中,这似乎都是一个非常基本且非常简单的问题,但我无法使其在 C# 中工作......

我有一个 383 双数组。当我散列它时,我得到一个非常奇怪的值

// this returns 134217728
let h = ((IStructuralEquatable) data).GetHashCode(EqualityComparer<double>.Default) 

恰好是ln h / ln 2 = 27 ...

如何在 C# 中获得一组可散列内容的结构散列码?

编辑更好的插图

尤其是下面的代码会产生愚蠢的结果

    var vala = new[] { 1f, 354652f, 3f };
    var valb = new[] { 1f, 56f, 545013f };
    var valc = new[] { 1f, 2584356483f,  68763948475f };

    var hashA = ((IStructuralEquatable)vala).GetHashCode(EqualityComparer<float>.Default);
    var hashB = ((IStructuralEquatable)valb).GetHashCode(EqualityComparer<float>.Default);
    var hashC = ((IStructuralEquatable)valc).GetHashCode(EqualityComparer<float>.Default);

哈希始终为796917760。 (虽然它似乎随着第一个数字而改变......)

结论

实际上,结论似乎是结构散列在 C# 中被破坏了。

(当然,实际上,它不是,因为其他人认为一个几乎恒定的函数是一个有效的散列函数.....)

【问题讨论】:

  • 哈希码通常很奇怪。你在期待什么?此外:我想你会同意134217728 实际上是偶数:)
  • 你想要数组全部内容的哈希码吗?
  • @MatthewWatson 是的,我想要数组内容的哈希码。这样我就可以将它与另一个数组的另一个哈希码进行比较。
  • @nicolas 这正是结构平等的意思;我提供了一个工作正常的例子。你能举一个例子,它不符合你的意图吗?你只是展示你获取一个哈希码,它告诉我们......好吧,绝对没有。您需要比较 2 个哈希码才能做任何有用的事情。
  • 它只有在将 EqualityComparer 传递给 GetHashCode() 时才有效,并且仅在 .Net 4 或更高版本中可用。

标签: c# .net hashcode


【解决方案1】:

您得到的值并不奇怪,因为GetHashCode 返回的值是不透明。你不应该能够从它们那里得到任何信息,所以任何值都和其他值一样奇怪。

也就是说,IStructuralEquatable 被宣传为您的问题的解决方案,它确实对我有用:

var a = new[] { 1f, 2f, 3f };
var b = new[] { 1f, 2f, 3f };

var hashA=((IStructuralEquatable)a).GetHashCode(EqualityComparer<float>.Default);
var hashB=((IStructuralEquatable)b).GetHashCode(EqualityComparer<float>.Default);

Console.WriteLine(hashA == hashB); // true

【讨论】:

  • 获取信息:structural hashcode - 基本上,如果它们包含相同的项目,它将允许两个集合报告为可比的,例如
  • @nicolas 你是什么意思“无效”?不存在无效哈希码之类的东西。 2 个哈希码可以不同,在这种情况下它们肯定代表不同的数据 - 或者它们可以相同,在这种情况下它们可能代表相同的数据,但我们必须通过 Equals 询问才能找到出... 绝对没有其他任何东西在哈希码中传达。
  • 它不执行结构哈希。这就是我在这里想要做的。你知道,通常的 hash([1 2 3 ]) = hash([1 2 3 ])
  • @nicolas 你把它比作什么?如果具有相同值不同数组(等)实例报告相同的哈希码,那么它工作正常。您不能仅从一个对象的哈希码中说出任何内容;你需要比较 2
  • @MarcGravell:谢谢,IStructuralEquatable 演员在那里,我并没有真正看到它。希望我今天没有在真实代码上这样做:)
【解决方案2】:

结构哈希码表示两个不同的对象(或集合)是否在语义上表示相同的数据。它工作正常;例如:

// invent some data
double[] vals1 = new double[383];
Random rand = new Random(12345);
for (int i = 0; i < vals1.Length; i++)
    vals1[i] = rand.NextDouble();
double[] vals2 = (double[])vals1.Clone();

// test with object rules
Console.WriteLine("{0} vs {1}",
    vals1.GetHashCode(), vals2.GetHashCode()); // 2 different numbers
Console.WriteLine(Equals(vals1, vals2)); // False

// now test using structural-equatable rules
IStructuralEquatable se1 = vals1, se2 = vals2;
var comparer = EqualityComparer<double>.Default;
Console.WriteLine("{0} vs {1}",
    se1.GetHashCode(comparer), se2.GetHashCode(comparer)); // 2 identical numbers
Console.WriteLine(se1.Equals(se2, comparer)); // True

【讨论】:

  • 所以你说我的代码是正确的(与上面相同)并且 134217728 是一个有效的哈希......
  • @nicolas 完全正确; 134217728 是一个完全合理的哈希值。在您将其与另一个哈希进行比较之前,它没有任何意义(非常刻意)。就像我之前说的:如果 2 个哈希值不同,它们肯定代表不同的数据;如果 2 个哈希值相同,则需要调用 Equals 来确定它们是否实际上相同。
  • 好的,所以我应该改写:我如何获得一个 good 哈希,而不是一个糟糕的哈希?
  • 我的意思是,来吧,你知道散列的全部目的是不碰撞,对吧?你可以想象,如果我得到 134217728,那是因为底层的哈希机制不足以达到这个目的。
  • @nicolas 哈希的目的是允许快速比较,适合在桶等中使用,理想情况下是最小化冲突。对于不同的值,不可能从不发生冲突,除非您的数据具有 134217728 是一个糟糕的哈希?这是一个奇怪的说法,除非事实证明你得到了大多数不同数组的134217728。再说一遍:您认为 134217728 有什么问题?请非常清楚地说明您为什么认为这是一个不好的价值。请举例说明您认为什么是好的价值?
猜你喜欢
  • 2011-12-31
  • 2016-09-16
  • 1970-01-01
  • 2013-03-17
  • 2019-05-25
  • 2013-04-15
  • 2014-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多