【问题标题】:Efficient Object Equality C#高效的对象相等 C#
【发布时间】:2012-12-18 17:47:43
【问题描述】:

我正在尝试提高以下(示例)代码的性能。

Object[] inputKeys = new Object[10];
inputKeys[0] = "4021";
inputKeys[1] = "3011";
inputKeys[2] = "1010";
inputKeys[3] = "1020";
inputKeys[4] = "1030";

然后比较输入键。

for (int i = 0; i < 5; i++)
{
    for (int j = 0; j < 5; j++)
    {
        bool result = inputKeys[i].Equals(inputKeys[j]);
    }
}

inputKeys 可以是stringint32DateTime 的所有类型。

.Equals 行的性能大幅下降,当它达到数百万次时。

关于如何提高这条线的性能(平等检查)有什么建议吗?

我试过这个: 使用下面类的数组而不是 Object 数组来保存键。在那里我保留了 Key 类型和键值。

public class CustomKey : IEquatable<CustomKey>{
    internal int KeyType { get; private set; }

    internal string ValueString { get; private set; }
    internal int ValueInteger { get; private set; }
    internal DateTime ValueDateTime { get; private set; }

    internal CustomKey(string keyValue)
    {
        this.KeyType = 0;
        this.ValueString = (string)keyValue;
    }

    internal CustomKey(int keyValue)
    {
        this.KeyType = 1;
        this.ValueInteger = (int)keyValue;
    }

    internal CustomKey(DateTime keyValue)
    {
        this.KeyType = 2;
        this.ValueDateTime = (DateTime)keyValue;
    }

    public bool Equals(CustomKey other)
    {
        if (this.KeyType != other.KeyType)
        {
            return false;
        }
        else
        {
            if (this.KeyType == 0)
            {
                return this.ValueString.Equals(other.ValueString);
            }
            else if (this.KeyType == 1)
            {
                return this.ValueInteger.Equals(other.ValueInteger);
            }
            else if (this.KeyType == 2)
            {
                return this.ValueDateTime.Equals(other.ValueDateTime);
            }
            else
            {
                return false;
            }
        }
    }
}

但性能更差。

【问题讨论】:

  • 你的问题是算法本身。您正在将每个项目与每个其他项目进行比较,这需要二次时间。如果您需要比较数百万个项目,您应该找到更好的方法。一种选择——不一定是最好的——是按类型划分数据,然后对其进行排序;这将使比较变得微不足道,并且只需要 n log n 时间。
  • 您期望有多少不同的值?例如,如果您期望数百万个项目但只有数万个值,那么一个简单的哈希表可能会解决问题。
  • 无法回答。最好的方法是少打equals。当它更频繁时它肯定不会变慢 - 我相信一个 equals 调用需要相同的时间。基本用途似乎选择不当(例如:首先检查哈希码,排序列表以进行较少的等于调用等)。这些是 50 多年的“知名”技术(指数、数据库)。最后,问题不在于 equals 的时间,而是您称其为数百万次 - 效率低下的算法。
  • @TomTom 是对的。不要浪费时间重写 Equals。 .Net Equals 已经处理了不同类型的比较。您的版本只是额外工作了一次。而是专注于 Equals 周围的代码。

标签: c#


【解决方案1】:

您的比较循环效率低下。我建议你尝试使用:

Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)

为该类型定义您的IEqualityComparer 并将其传递给该方法。你不会得到一个布尔值,但你会得到一个 IEnumerable 包含没有重复的列表。

【讨论】:

  • 谢谢,但是当我运行分析器(ANTS)时,下降仅在相等性检查中,在循环中可以忽略不计。这就是为什么我说我只想改善平等。
  • 我同意这不是 Equals 操作,而是他进行循环的方式。
  • 将 HashCodes 的使用与比二次算法更好的算法结合起来,它的性能应该会更好。也建议阅读:stackoverflow.com/questions/11515991/…
【解决方案2】:

作为算法效率的一个例子,你的第一个代码可以重写

for (int i = 0; i < 5; i++)
{
    for (int j = i; j < 5; j++)
    {
        bool result = inputKeys[i].Equals(inputKeys[j]);
    }
}

因为 x.Equals(y) 将给出与 y.Equals 相同的结果,所以您无需同时检查两种方式。 http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx

Equals 的新实现应该遵循所有的保证

x.Equals(y) 返回与 y.Equals(x) 相同的值。

【讨论】:

  • 很好的观察,值得注意的是,将 j 初始化为 i+1 将节省 O(n) 次查询。
【解决方案3】:

正如 cmets 中所说,您的算法的主要负担是您必须将所有内容与所有内容进行比较,这会影响您的性能。对于 100K 元素,这意味着 100k^2 ......或大约 10K 百万组合......你可以看到你有问题的地方。最好的选择是修改算法,但是,如果您仍然确定或没有任何其他选择,请考虑:

先划分对象,稍后比较:

示例:如果您有 100K 个对象均匀分布,您将拥有 33K 个整数、33K 个字符串和 33K 个日期时间,然后您可以将它们相互比较并忽略它们之间的组合。

100K^2 = 10K 百万

(30K^2) * 3 = 2700 百万组合 + 100K 对其列表中的每个元素进行排序

扩展您的群组

如果您不太关心内存,您可以对结果进行哈希处理以进一步优化您的组。基本上构建一个网格...这非常具体,具体取决于您的问题

这背后的想法是隔离不能真正相等的事物,这是对先前想法的扩展,但组越多,组越小,你的表现越快

这样你就可以有 10 个组

  • 少于 5 个字符的字符串
  • 5 到 50 个字符之间的字符串
  • 超过 50 个字符的字符串

等等……

如果您重做数学运算(同样,对于均匀分布的样本)

总迭代次数 = 10K^2 * 10 + 100K ~ 1 亿次迭代(10 组 + 组成这些组的价格)

实际复杂度 = (n/m)^2 * m + n(其中 n = 元素数,m = 假设均匀分布的组数。

【讨论】:

    【解决方案4】:

    尝试获取每个对象的哈希码并将它们与object.GetHashCode() 进行比较。不确定调用GetHashCode() 几百万次的开销,但比较两个整数可能会比Equals(object) 方法快很多。

    【讨论】:

      【解决方案5】:

      使用哈希表(或更好的字典)来存储您的项目。 您的方法具有 (N^2) 的顺序,通过使用哈希表,您可以将运行时间复杂度降低到 O(N),其中 N 是数字。

      为此,使用哈希键创建一个哈希表,如果发生冲突,将项目添加到链表中。当只需要检查同一桶中的对象是否相等时,不应该太多。

      我希望这很清楚并且有帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-05
        • 1970-01-01
        • 1970-01-01
        • 2011-03-11
        • 2011-07-16
        相关资源
        最近更新 更多