【问题标题】:Intersect between two lists not working两个列表之间的相交不起作用
【发布时间】:2011-11-29 17:03:28
【问题描述】:

我有两个列表见下文.....结果返回为空

List<Pay>olist = new List<Pay>();
List<Pay> nlist = new List<Pay>();
Pay oldpay = new Pay()
{
    EventId = 1,
    Number = 123,                        
    Amount = 1
};

olist.Add(oldpay);
Pay newpay = new Pay ()
{
   EventId = 1,
    Number = 123,                        
    Amount = 100
};
nlist.Add(newpay);
var Result = nlist.Intersect(olist);

有什么线索吗?

【问题讨论】:

  • 假设 Pay 相等是 EventID、Number 和 Amount,这两个列表中没有任何共同点,因此没有任何交叉。换句话说,你还没有在这里定义平等。
  • 这里没有定义相等是什么意思?唯一不同的元素是 Amount = 100
  • 问题中没有任何内容表明为什么 oldpay 应该等于newpay

标签: c# linq list


【解决方案1】:

您需要覆盖 Pay 类中的 EqualsGetHashCode 方法,否则 Intersect 不知道何时认为 2 个实例相等。它怎么会猜到是EventId 决定了平等? oldPaynewPay 是不同的实例,因此默认情况下它们不相等。

您可以像这样覆盖Pay 中的方法:

public override int GetHashCode()
{
    return this.EventId;
}

public override bool Equals(object other)
{
    if (other is Pay)
        return ((Pay)other).EventId == this.EventId;
    return false;
}

另一种选择是实现IEqualityComparer&lt;Pay&gt; 并将其作为参数传递给Intersect

public class PayComparer : IEqualityComparer<Pay>
{
    public bool Equals(Pay x, Pay y)
    {
        if (x == y) // same instance or both null
            return true;
        if (x == null || y == null) // either one is null but not both
            return false;

        return x.EventId == y.EventId;
    }


    public int GetHashCode(Pay pay)
    {
        return pay != null ? pay.EventId : 0;
    }
}

...

var Result = nlist.Intersect(olist, new PayComparer());

【讨论】:

  • 或者您可以编写自己的比较器:msdn.microsoft.com/en-us/library/234b841s.aspx
  • @mydogisbox,是的,当您发表评论时,我实际上是在编辑我的答案以提及这一点;)
  • 或者你可以让Pay 输入一个struct 来为你完成它,虽然默认实现很慢,因为它使用反射。
  • @Gebb,默认实现不使用反射,它对对象进行二进制比较。但无论如何,结构的默认相等比较比较 all 字段,这可能不是这里想要的行为。
  • @ThomasLevesque,但是文档为什么这么说呢? msdn.microsoft.com/en-us/library/2dts52z7.aspx
【解决方案2】:

Intersect 可能仅在Pay 的相同实例同时在两个List 中时添加对象。由于oldPaynewPay 是分开实例化的,因此它们被认为是不相等的。

Intersect 使用Equals 方法来比较对象。如果您不覆盖它,它会保持与 Object 类相同的行为:仅当两者都是对象的相同实例时才返回 true

您应该覆盖Pay 中的Equals 方法。

   //in the Pay class
   public override bool Equals(Object o) {
      Pay pay = o as Pay;
      if (pay == null) return false;
      // you haven't said if Number should be included in the comparation
      return EventId == pay.EventId; // && Number == pay.Number; (if applies)
   }

【讨论】:

    【解决方案3】:

    对象是引用类型。当您创建两个对象时,您有两个唯一的引用。他们会比较相等的唯一方法是如果你这样做:

    object a = new object();
    object b = a;
    

    在这种情况下,(a == b) 为真。阅读reference vs value 类型和objects

    正如 Thomas Levesque 指出的那样,要解决您的问题,请覆盖 Equals 和 GetHashCode。

    【讨论】:

      【解决方案4】:

      正如其他人所指出的,您需要提供适当的覆盖以使Intersect 正常工作。但是,如果您不想打扰覆盖并且您的用例很简单,还有另一种方法。这假设您要匹配 EventId 上的项目,但您可以修改它以比较任何属性。请注意,这种方法可能比调用 Intersect 更昂贵,但对于小型数据集可能无关紧要。

      List<Pay> intersectedPays = new List<Pay>();
      
      foreach (Pay o in olist)
      {
          var intersectedPay = nlist.Where(n => n.EventId == o.EventId).SingleOrDefault();
      
          if (intersectedPay != null)
              intersectedPays.Add(intersectedPay);
      }
      
      List<Pay> result = intersectedPays;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-11
        • 2021-06-28
        • 2018-12-29
        • 2018-08-17
        • 1970-01-01
        • 1970-01-01
        • 2021-03-18
        • 1970-01-01
        相关资源
        最近更新 更多