c# - 除了方法在 linq 中如何工作

标签 c# performance linq comparison hashtable

我有类(class):

class SomeClass
{
   public string Name{get;set;}
   public int SomeInt{get;set;}
}


class SomeComparison: IEqualityComparer<SomeClass>
{
     public bool Equals(SomeClass s, SomeClass d)
     {
         return s.Name == d.Name;
     }

     public int GetHashCode(SomeClass a)
     {
         return (a.Name.GetHashCode() * 251);
     }
}

我还有两个大的List<SomeClass>称为 list1list2

以前我有:

 var q = (from a in list1
         from b in list2
         where a.Name != b.Name
         select a).ToList();

执行大约需要 1 分钟。现在我有:

var q =  list1.Except(list2,new SomeComparison()).ToList();

这需要不到 1 秒的时间!

我想了解 Except 方法的作用。该方法是否为每个列表创建一个哈希表,然后执行相同的比较?如果我要执行很多这样的比较,我应该创建一个哈希表吗?


编辑

现在我没有列表,而是有两个 HashSet<SomeClass>称为 hashSet1hashSet2

当我这样做时:

   var q = (from a in hashSet1
           form b in hashSet2
           where a.Name != b.Name
           select a).ToList();

这仍然需要很长时间...我做错了什么?

最佳答案

您的猜测很接近 - Linq to Objects Except扩展方法使用 HashSet<T>在内部对于传入的第二个序列 - 这允许它在 O(1) 中查找元素,同时迭代第一个序列以过滤掉第二个序列中包含的元素,因此总体工作量为 O(n+m) 其中n 和 m 是输入序列的长度 - 这是您希望做的最好的事情,因为您必须至少查看每个元素一次。

关于如何实现的回顾,我推荐 Jon Skeet 的 EduLinq 系列,这里是 Except 的实现部分。以及指向 full chapter 的链接:

private static IEnumerable<TSource> ExceptImpl<TSource>(
    IEnumerable<TSource> first,
    IEnumerable<TSource> second,
    IEqualityComparer<TSource> comparer)
{
    HashSet<TSource> bannedElements = new HashSet<TSource>(second, comparer);
    foreach (TSource item in first)
    {
        if (bannedElements.Add(item))
        {
            yield return item;
        }
    }
}

另一方面,您的第一个实现会将第一个列表中的每个元素与第二个列表中的每个元素进行比较 - 它正在执行 cross product .这将需要 nm 次操作,因此它将在 O(nm) 中运行 - 当 n 和 m 变大时,它变得非常慢非常快。 (这个解决方案也是错误的,因为它会创建重复的元素)。

关于c# - 除了方法在 linq 中如何工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10269610/

相关文章:

c# - 在 C# : Add Quotes around string in a comma delimited list of strings 中

java - Elasticsearch查询不会间歇性地获取结果

c# - 如何最好地优化这一小段 C# Linq 代码

jquery - 无法使用ajax和linq将数据保存到数据库

c# - 尴尬的继承问题

c# - 将 DateTime 存储到 cookie 中的最佳方法是什么?

c# - 在转发器中处理文件上传

c# - 使用条件将一次性大型 IEnumerable<T> 分成两半

c# - 通过反射设置变量

ruby-on-rails - 每次在同一 Controller 中使用实例变量时是否都重新计算?