【问题标题】:Best way to checksum a collection of variables?校验和一组变量的最佳方法?
【发布时间】:2015-02-02 22:15:13
【问题描述】:

我有一个具有 9 个属性的对象:整数、字符串、小数、guid。

我有一个这个对象的数组,长度为 200 万条记录。

我想为此对象的属性创建一个不会与任何其他记录冲突的字符串哈希/校验和。

在 C# 中执行此操作的最佳方法是什么?我考虑过 concat 和 md5,但如果我有 a=1 b=12 或 a=11 b=2 它们会同时连接到 112,则 concat 可能会产生冲突。

编辑:也许 CHECKSUM 是一个更好的词?我只需要进行快速比较而不是直接进行对象比较,我必须对每个字段进行值比较。

【问题讨论】:

  • 您考虑过使用唯一键吗?
  • 你的每个对象都有一组独特的属性吗?
  • Guid 已经是全球唯一的了,我猜?除非在多个对象中重用相同的 Guid。
  • 由于哈希值为Int32(如果您正在寻找GetHashCode 实现),您的可能性略高于4e9,并且您的类发生冲突的可能性要大得多;这就是为什么根据 Dirichlet 原理 没有这样的哈希
  • 哈希总是会发生冲突,即使是最强的加密哈希。它们保证具有不同哈希的对象永远不会相等,而不是相反。它们不是键,它们是避免昂贵的价值比较的一种方式。如果要覆盖 GetHash,只需对对象字段的哈希值进行异或运算

标签: c#


【解决方案1】:

我必须对每个字段进行值比较

如果这是您的最终需求,则没有计算值可以避免比较单个字段,除非该计算值对于任何字段值组合都是唯一的,例如(作为示例)连接所有字段值的字符串每个对象,但请记住,将某些值转换为字符串可能会导致近似值,从而导致对象之间的错误不匹配(尤其是浮点数)。

逐字段比较是最准确的,而哈希/校验和计算并不意味着准确比较,而仅用于索引,或作为初步检查以避免更密集的计算(如您的),或其他目标不需要逐个字段。

您最终可以编写一个只读属性,仅在需要时计算一次值,并将其存储为隐藏字段,例如:

    public class _Object
    {
        public Int32 IntField;
        public String StringField;
        public Decimal DecimalField;
        public Guid GuidField;

        private string m_UniqueKey;
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        public string UniqueKey
        {
            get
            {
                if (m_UniqueKey == null)
                {
                    m_UniqueKey = IntField.ToString()
                                + "|" + (StringField ?? string.Empty)
                                + "|" + DecimalField.ToString("F6", CultureInfo.InvariantCulture)
                                + "|" + GuidField.ToString("X");
                }
                return m_UniqueKey;
            }
        }
    }

上面的代码示例只计算一次 m_UniqueKey(如果它为 null),并使用任意字符作为字段值之间的分隔符。它还尝试将十进制值格式化为任意选择的精度。

如果您需要哈希/校验和值,您可以尝试实现 GetHashCode() 并依赖它,但在这种情况下,您也应该包含所有重要字段或其中的一部分。

问候,
丹尼尔。

【讨论】:

    猜你喜欢
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 2012-02-06
    相关资源
    最近更新 更多