【问题标题】:C# Linq intersect/except with one part of objectC# Linq 与对象的一部分相交/除外
【发布时间】:2012-05-24 21:23:40
【问题描述】:

我有课:

class ThisClass
{
  private string a {get; set;}
  private string b {get; set;}
}

我想使用 Linq 的 Intersect 和 except 方法,即:

private List<ThisClass> foo = new List<ThisClass>();
private List<ThisClass> bar = new List<ThisClass>();

然后我分别填写这两个列表。例如,我想做以下事情(我知道这不对,只是伪代码):

foo[a].Intersect(bar[a]);

我该怎么做?

【问题讨论】:

  • 你想要什么?从foo[a].Intersect(bar[a]);这一行用文字解释你想要什么。

标签: c# linq intersect except


【解决方案1】:

也许

// returns list of intersecting property 'a' values
foo.Select(f => f.a).Intersect(bar.Select(b => b.a));

顺便说一句,a 的属性应该是公开的。

【讨论】:

  • 这会返回一个属性集合。我一直在寻找对象集合的返回。请参阅下面来自 Patryk 的评论。
【解决方案2】:
foo.Select(x=>x.a).Intersect(bar.Select(x=>x.a))

【讨论】:

    【解决方案3】:

    如果您想要一个想要相交的单个属性的列表,那么所有其他漂亮的 LINQ 解决方案都可以正常工作。 但!但是,如果您想与整个班级相交并因此使用List&lt;ThisClass&gt; 而不是List&lt;string&gt;,则必须编写自己的相等比较器。

    foo.Intersect(bar, new YourEqualityComparer());
    

    Except 相同。

    public class YourEqualityComparer: IEqualityComparer<ThisClass>
    {
    
        #region IEqualityComparer<ThisClass> Members
    
    
        public bool Equals(ThisClass x, ThisClass y)
        {
            //no null check here, you might want to do that, or correct that to compare just one part of your object
            return x.a == y.a && x.b == y.b;
        }
    
    
        public int GetHashCode(ThisClass obj)
        {
            unchecked
            {
                var hash = 17;
                                //same here, if you only want to get a hashcode on a, remove the line with b
                hash = hash * 23 + obj.a.GetHashCode();
                hash = hash * 23 + obj.b.GetHashCode();
    
                return hash;    
            }
        }
    
        #endregion
    }
    

    【讨论】:

    • 这正是我想要的。在不到几秒钟的时间内比较了两个 250K 列表。谢谢!
    【解决方案4】:

    您应该创建 IEqualityComparer。您可以将 IEqualityComparer 传递给 Intersect() 方法。这将帮助您更轻松地获得 List(与 bar 相交)。

    var intersectionList = foo.Intersect(bar, new ThisClassEqualityComparer()).ToList();
    
    
    class ThisClassEqualityComparer : IEqualityComparer<ThisClass>
    {
    
        public bool Equals(ThisClass b1, ThisClass b2)
        {
            return b1.a == b2.a;
        }
    
    
        public int GetHashCode(Box bx)
        {
           // To ignore to compare hashcode, please consider this.
           // I would like to force Equals() to be called
           return 0;
        }
    
    }
    

    【讨论】:

    • 你不应该像这样从哈希码返回0。这将完全扼杀性能。您应该改用 a 的哈希码。
    【解决方案5】:

    想要的效果到底是什么?当通过 a 的唯一值标识两个 ThisClass 实例时,您想要获得由类中所有 a 组成的字符串列表,还是获得 ThisClass 的列表?

    如果是前者,@lazyberezovksy 和@Tilak 的两个答案应该有效。如果是后者,则必须覆盖 IEqualityComparer&lt;ThisClass&gt;IEquatable&lt;ThisClass&gt; 以便 Intersect 知道是什么使 ThisClass 的两个实例等效:

     private class ThisClass : IEquatable<ThisClass>
     {
         private string a;
    
         public bool Equals(ThisClass other)
         {
            return string.Equals(this.a, other.a);
         }
     }
    

    然后你可以打电话:

     var intersection = foo.Intersect(bar);     
    

    【讨论】:

    • 在实现IEquatable 时,您始终需要覆盖GetHashCode。既然你不这样做,这将行不通。
    【解决方案6】:

    不确定与相交和比较相比的速度,但如何:

    //Intersect
    var inter = foo.Where(f => bar.Any(b => b.a == f.a));
    //Except - values of foo not in bar
    var except = foo.Where(f => !bar.Any(b => b.a == f.a));
    

    【讨论】:

    • 这是一个 O(n * m) 算法,而 IntersectExcept 都是 O(n + m)。这让你的情况变得更糟。它还会多次迭代bar,这在各种情况下都可能是一个主要问题(它可能不会在每次迭代中产生相同的结果,它可能会在每次迭代时查询数据库或执行昂贵的计算,它可能会产生副作用迭代时引起的,等等。
    • @Servy 答案的扩展:只需查看source code 即可评估 Intersect / Except 方法的复杂性。
    【解决方案7】:

    我知道这是旧的,但你不能也覆盖类本身的 Equals 和 GetHashCode 吗?

    class ThisClass
    {
      public string a {get; set;}
      private string b {get; set;}
    
      public override bool Equals(object obj)
      {
        // If you only want to compare on a
        ThisClass that = (ThisClass)obj;
        return string.Equals(a, that.a/* optional: not case sensitive? */);
      }
    
      public override int GetHashCode()
      {
        return a.GetHashCode();
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多