如何根据属性的部分信息比较两个对象列表?

时间:2015-04-08 19:38:14

标签: c# list

让我们假设您想基于截断的(我认为这是单词)版本的DateTime属性来比较两个对象列表:

public class MyObject 
{
    public DateTime SomeDate {get;set;}
}

通常比较列表:

bool didItWork = myFirstList.Intersect(MySecondList).Any();

除了我需要根据上面的DateTime属性进行检查外,所有这里都很好和很好:

bool didItWork = myFirstLIst.Intersect(MySecondList).Any(someIntuitivePredicate);

正如您所看到的,我不知道直观谓词是什么。

对于踢球者,我想在进行比较时从SomeDate中删除时间部分:

dateWithoutTime = myObject.SomeDate.Date;

时间与实际日期并不重要。

3 个答案:

答案 0 :(得分:1)

据我所见,您有两种选择:

  1. 实现自定义IEqualityComparer并将其传递给Intersect overload that takes an IEqualityComparer
  2. 或者

    1. 使用嵌套Intersect模拟Any

      bool didItWork = myFirstList.Any(item1 => 
                       mySecondList.Any(item2 =>
                       item1.SomeDate.Date == item2.SomeDate.Date));
      

      显然,item1.SomeDateDate == item2.SomeDate.Date可以被任意谓词替换。

      这里是那些喜欢LINQ查询语法的人的替代版本:

      bool didItWork = (from item1 in myFirstList
                        from item2 in mySecondList
                        where item1.SomeDate.Date == item2.SomeDate.Date).Any();
      

答案 1 :(得分:1)

您可以使用Intersect方法的重载,该方法也将IEqualityComparer实现作为输入:

bool didItWork = myFirstList.Intersect(MySecondList, new MyEqualityComparer()).Any();

// ...

public class MyEqualityComparer : IEqualityComparer<MyObject>
{
    public bool Equals(MyObject x, MyObject y)
    {
        return x.SomeDate.Date == y.SomeDate.Date;
    }

    public int GetHashCode(MyObject x)
    {
        return x.SomeDate.Date.GetHashCode();
    }
}

答案 2 :(得分:1)

看到你没有注明答案,我会对此采取行动,但答案确实是很好的努力,但这是你的模糊问题定义的结果。甚至你的评论&#34;如果任何一个列表中的任何项目在另一个列表中不存在&#34;措辞有点笨拙。不要试图烧烤你,但要记住这一点。在处理集合操作时,您必须退后一步,并仔细考虑您想要完成的任务。我将这样解释您的目标,如果这不正确,您应该使用更明确定义的问题定义来更新您的问题:

  

我想检查并确保对于myFirstList中的每个项目,   mySecondList中有一个项目,具有相同的SomeDate.Date和副   反之亦然。

如果您截断日期的时间,那么我会推测可能存在两个具有相同日期的项目。如果不是这种情况,则有更简单的方法可以采用方法,例如连接或交叉列表,并检查结果是否等于原始数量(这将验证所有项目是否匹配)。使用连接或交叉的其他答案不太合适,因为它们使用.Any(),如果其中一个项匹配,则返回true,而不是全部。

.All将确保一个列表中的所有项都符合某些条件。在这种情况下,请确保每个项目在第二个列表中都匹配。

bool isListEqual = myFirstList.All(x=> 
      mySecondList.Select(y=>y.SomeDate.Date).Contains( x.SomeDate.Date) )

isListEqual = isListEqual && mySecondList.All(x=> 
      myFirstList.Select(y=>y.SomeDate.Date).Contains( x.SomeDate.Date) )

我们这两个方向都是为了确保第二个列表中没有项目,而第一个列表中没有匹配的项目。

如果我们知道没有重复项,另一种方法是加入列表并计算结果以确保它们与原件匹配。或者我们可以简单地消除重复以生成不同的列表。您还可以使用SetEquals的hashset或IEnumerable的SequenceEquals。如果您知道结果已经按特定顺序排列,则SequenceEquals会更好。

   var firstDates = myFirstList.Select(l=>l.SomeDate.Date).Distinct().OrderBy(d=>d).ToList();
   var secondDates = mySecondList.Select(l=>l.SomeDate.Date).Distinct().OrderBy(d=>d).ToList();

   bool isListEqual = firstDates.SequenceEqual(secondDates);

我认为你应该从中采取的最重要的事情是,方法取决于你可以对输入数据做出的假设。

这个问题涵盖了几种方法,以及与之相关的副本:

Check if two lists are equal