【问题标题】:C# Is it possible to generate an identifier for array of double valuesC#是否可以为双值数组生成标识符
【发布时间】:2021-08-20 18:04:13
【问题描述】:

我正在处理现有数据并且有包含数组 double[23] 和 double[46] 的记录。数组中的值可以在多条记录中相同。我想生成一个 id(可能是一个 int)来唯一标识每个数组中的值。

应用程序中有些地方我需要根据数组中相同的值对记录进行分组。虽然有很多方法可以查询这个,但我希望有一个单一的 int 字段(或类似的东西)来分组。这确实有助于简化查询,尤其是有助于使用报告工具,在较小的单个字段上进行分组会大有帮助。

我想生成一个哈希码,但我知道对于每个具有匹配值的 double[],这些代码不保证相同。我曾尝试实施

((IStructuralEquatable)combined).GetHashCode(EqualityComparer<double>.Default);

比较结构和数据,但我不认为这是保证匹配另一个具有相同值的 double[]。

也许某种形式的校验和会起作用,但我承认我在实现某些东西时遇到了麻烦。我正在寻找建议/方向。

这是 3 个样本记录的数据。记录 1 和 3 中的数据相同,因此生成的 id 应该与这些数据匹配。 32.7,48.9,55.9,48.9,47.7,46.9,45.7,44.4,43.4,41.9,40.4,38.4,36.7,34.4,32.4,30.4,27.9,25.4,22.4,19.4,16.4,13.4,10.4,47.9 40.8,49.0,50.0,49.0,47.8,47.0,45.8,44.5,43.5,42.0,40.5,38.5,36.8,34.5,32.5,30.5,28.0,25.5,22.5,19.5,16.5,13.5,10.5,48.0 32.7,48.9,55.9,48.9,47.7,46.9,45.7,44.4,43.4,41.9,40.4,38.4,36.7,34.4,32.4,30.4,27.9,25.4,22.4,19.4,16.4,13.4,10.4,47.9

如果不检查所有数据,这可能是不可能的,但希望有更好的解决方案来简化应用程序并提高速度。

目标是在现有记录中添加一个新的 id 字段来表示数组数据。这样一来,将记录传递到报告工具中就可以轻松地在一个字段上组合在一起,而不是检查每条记录上的整个数组。

我很欣赏任何方向。

编辑 - 我在尝试时遇到的一些问题(以防它帮助某人)

在最初试图理解这一点时,我调用了这段代码(它是 .NET 的一部分)。我知道这些函数会将数组的 散列在一起(在这种情况下只有 8 个值)。我不认为它包括数组句柄。结果并不像预期的那样,因为根据下面的注释行在 .NET 中纠正了一个错误 MS。通过修复,我得到了更好的结果。

int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
        if (comparer == null)
            throw new ArgumentNullException("comparer");
        Contract.EndContractBlock();

        int ret = 0;

        for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++) {
            ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(i))); 
//.NET 4.6.2, in .NET 4.5.2 it is ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(0))) 
        }

        return ret;
    }

    internal static int CombineHashCodes(int h1, int h2) {
        return (((h1 << 5) + h1) ^ h2);
    }

我对其进行了修改以处理超过 8 个值,但仍然有一些不匹配的哈希值。后来我确定问题出在数据中;我不知道有些记录有一些双精度数超过一位小数(应该四舍五入)。这当然改变了哈希。现在我的数据是一致的,我看到了匹配的哈希值;任何具有相同值的数组都有相同的哈希值。

【问题讨论】:

  • 哈希码可能是您可以使用单个值获得的最接近的值,但有可能发生冲突。为了 100% 的确定性,您需要循环并比较每个值。
  • 可能想了解更多关于 C# GetHashCode 的信息,它并不是真正的加密哈希,更便于检查是否有不同。请参阅 stackoverflow.com/a/7425150/1462295 和注意 Two unequal objects are not guaranteed to have unequal hashcodes,这更关注单个 32 位哈希值。
  • @Alejandro 我希望有另一种方法,但据我了解,gethashcode 总是有可能发生冲突,因此即使数据相同,某些数组 id 也可能不匹配。我认为 IStructuralEquatable 代码可能会比较数组结构和数据,但似乎仍然有可能发生冲突,因此 id 可能不会一直唯一地表示数据。感谢您的意见。
  • @BurnsBA 感谢 BurnsBA。我在学习过程中学到了一些知识,并且了解可能会发生碰撞。我希望有另一种算法来识别数组,但看起来不太有希望。我没有绑定到 int,只是在寻找比比较每个记录的整个数组更好的东西,但不确定我会摆脱它。也许加密哈希可能没有冲突,但我必须阅读它,因为我还没有使用它的经验。
  • 比较 double[23] 中可能的值组合的数量与 int 的可能值的数量,你会发现这是行不通的。

标签: c# arrays hash checksum


【解决方案1】:

我想生成一个哈希码,但我知道对于每个具有匹配值的 double[],这些代码不保证相同

恰恰相反,设计要求哈希函数为相等的输入返回相等的哈希值。例如,0 是哈希函数的一个很好的起点,对于相等的行返回值 0。其他一切都只是为了减少误报而进行的优化。

如果不检查所有数据,也许这是不可能的

你当然需要检查所有数据,否则你会怎么做?

但是你的实现被破坏了。数组的默认哈希函数对数组本身的句柄进行哈希处理,因此具有相同数据的不同数组实例将显示为不同。您要做的是使用 HashCode 实例和 Add() 数组中的每个元素来获得正确的哈希码。

【讨论】:

  • 感谢您的意见。我不希望通过哈希运行这些以动态比较它们,我希望生成一个新字段来唯一地表示数据数组以供以后使用(尤其是报告)。我尝试了一些方法,但看到不同的数组数据出现了相同的哈希码。诚然,我在散列或校验和方面没有很多经验,所以如果我可能误解了,我深表歉意。也许您建议使用加密哈希函数。
  • 现在您所描述的与原始问题相反。我再说一遍,正确的哈希函数具有相同输入的结果相等的属性。它不会返回唯一值(除非您处于退化的情况下),并且它不保证不同输入的不同值(尽管如果您在数学方面足够好,或者使用像 HashCode 这样的正确实现,将 通常是真的)。​​
  • 抱歉措辞/描述不佳。对于“正确的哈希函数具有相同输入的结果相等的属性” - 这对我不起作用;我实际上用相同的输入得到了不同的值。但是,我在 .NET 4.5.2 中发现了一个无法正常工作的错误。它肯定在 4.6.2 中修复,可能更早。我为整个阵列实施了一个快速版本的修复程序,现在这些似乎具有相同的结果。我会继续努力 - 很抱歉造成混乱。
  • “我实际上用相同的输入得到了不同的值”——我解释说,你使用了错误的哈希函数。结果是正确的,你只是解释错了。而且我不知道您指的是什么错误,哈希函数在任何地方都一样,它们是一个数学概念。
  • 仅供参考,我在上面添加了一个编辑,因为评论太长了。它解释了我在尝试根据您的建议将数组值散列在一起来获取匹配散列时遇到的一些问题。感谢您的指导。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-10
相关资源
最近更新 更多