LINQ Except / Distinct仅基于少数列,不添加重复项

时间:2015-06-09 09:05:29

标签: c# .net linq distinct except

对不起令人困惑的头衔。但我无法想出更简单的东西。

我得到了以下课程。

public class Foo
{
    public FooId int { get; set; }

    public FooField string { get; set; }

    //some more fields here....
    //....
    //....

    public DateTime CreatedDate { get; set; }
}

我需要循环浏览某些内容并向Foo添加一系列List<Foo>,但根据FooIdFooField的组合,它不应重复。

所以我正在尝试如下

List<Foo> foos = new List<Foo>();

foreach (Bar item in blah.Bars)
{
    //Some code here to get the foos from the item
    List<Foo> processedFoos = item.GetFoos();

    //The problem is with below line
    foos.AddRange(processedFoos.Except(foos));
}

Except会添加所有记录,并重复FooIdFooField组合,因为CreatedDate对所有记录都是唯一的。

但我需要忽略CreatedDate并添加那些不违反唯一组合的记录。

我可以在这做什么? ExceptDistinct?还有其他选择吗?

最重要的是,如何?

4 个答案:

答案 0 :(得分:7)

您需要覆盖Equals中的Foo,或实施IEqualityComparer<Foo>,以便Except可以判断两个Foo值何时相等。例如:

public sealed class FooComparer : IEqualityComparer<Foo>
{
    public bool Equals(Foo x, Foo y)
    {
        return x.FooId == y.FooId && x.FooField == y.FooField;
    }

    public int GetHashCode(Foo foo)
    {
        // Note that if FooField can be null, you'll need to account for that...
        return foo.FooId ^ foo.FooField.GetHashCode();
    }
}

然后:

 foos.AddRange(processedFoos.Except(foos, new FooComparer()));

答案 1 :(得分:1)

ExceptDistinct都将根据对象的Equals实现(这是默认的相等比较器)来比较项目。他们也都有超载IEqualityComparer<T>

您可以实现此界面(请参阅the documentation获取示例),仅比较您需要的字段并将其传递给Except

 foos.AddRange(processedFoos.Except(foos, comparer));

答案 2 :(得分:1)

ExceptDistinct都有一个需要IEqualityComparer的重载。您可以实现一个仅比较所需的属性。

另一种方法是按FooId和FooField进行分组,并从每组中取出第一个元素:

processFoos.GroupBy(foo => new {foo.FooId, foo.FooField})
.Select(g => g.First());

答案 3 :(得分:0)

我认为您应该改变选择不重复记录的方式:

processedFoos.Where(x => !foos.Any(y => y.FooId == x.FooId && y.FooField == x.FooField))