C# Linq 与对象的一部分相交/除外

问题描述 投票:0回答:8

我有课:

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]);

我该怎么做?

c# linq intersect except
8个回答
41
投票

如果您想要一个要相交的单个属性的列表,那么所有其他漂亮的 LINQ 解决方案都可以正常工作。 但!如果你想在整个类上相交,结果有一个

List<ThisClass>
而不是
List<string>
,你必须编写自己的相等比较器。

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
}

38
投票

也许

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

顺便说一句,属性

a
应该是公开的。


8
投票

不确定与相交和比较相比的速度,但怎么样:

//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));

1
投票
foo.Select(x=>x.a).Intersect(bar.Select(x=>x.a))

0
投票

到底想要的效果是什么?当通过

a
的唯一值标识两个
ThisClass
实例时,您想要获取由类中所有
ThisClass
组成的字符串列表,还是
a
列表?

如果是前者,@lazyberezovksy 和 @Tilak 的两个答案应该有效。如果是后者,您必须重写

IEqualityComparer<ThisClass>
IEquatable<ThisClass>
,以便
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);     

0
投票

我知道这已经很旧了,但是你不能重写类本身的 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();
  }
}

0
投票

您可以尝试以下方法。这是一个 lambda 表达式,其中我们将项目定义为 ThisClass 变量,并将等式定义为 foo 和 bar 之间的内部 lambda 表达式。在 where 子句中,我们根据字段 a 获取满足等式 creteria 的元素,并且因为这返回匿名类型的类,所以我们选择 q.item 来表示 ThisClass 中满足等式的所有项,并给出 IEnumerable 类型。

IEnumerable<ThisClass> Intersection = 
foo.Select(x => new 
{
  item = x, 
  equality = bar.Any(y => y.a.Equals(x.a))
}).Where(w => w.equality).Select(q => q.item);

-3
投票

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

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;
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.