LINQ Except/Distinct 仅基于几列,不添加重复项
LINQ Except/Distinct based on few columns only, to not add duplicates
请原谅我的标题令人困惑。但是我想不出更简单的东西。
我已经低于class。
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>
,但根据 FooId
和 [=16= 的组合,它不应重复].
所以我正在尝试如下
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
添加所有记录并复制 FooId
和 FooField
组合,因为 CreatedDate
对于所有记录都是唯一的。
但我需要忽略 CreatedDate
并只添加那些不违反唯一组合的记录。
我可以在这里做什么? Except
? Distinct
?还有其他选择吗?
最重要,怎么样?
Except
和 Distinct
都将根据对象的 Equals
实现来比较项目(这是默认的相等比较器)。它们也都有采用 IEqualityComparer<T>
的重载。
您可以实现此接口(参见 the documentation 的示例)仅比较您需要的字段并将其传递给 Except
:
foos.AddRange(processedFoos.Except(foos, comparer));
您需要覆盖 Foo
中的 Equals
,或者实施 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()));
我认为你应该改变 select 不重复记录的方式:
processedFoos.Where(x => !foos.Any(y => y.FooId == x.FooId && y.FooField == x.FooField))
Except
和 Distinct
都有一个需要 IEqualityComparer
的重载。您可以实现一个来仅比较您需要的属性。
另一种方法是按 FooId 和 FooField 分组,然后从每组中取出第一个元素:
processFoos.GroupBy(foo => new {foo.FooId, foo.FooField})
.Select(g => g.First());
请原谅我的标题令人困惑。但是我想不出更简单的东西。
我已经低于class。
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>
,但根据 FooId
和 [=16= 的组合,它不应重复].
所以我正在尝试如下
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
添加所有记录并复制 FooId
和 FooField
组合,因为 CreatedDate
对于所有记录都是唯一的。
但我需要忽略 CreatedDate
并只添加那些不违反唯一组合的记录。
我可以在这里做什么? Except
? Distinct
?还有其他选择吗?
最重要,怎么样?
Except
和 Distinct
都将根据对象的 Equals
实现来比较项目(这是默认的相等比较器)。它们也都有采用 IEqualityComparer<T>
的重载。
您可以实现此接口(参见 the documentation 的示例)仅比较您需要的字段并将其传递给 Except
:
foos.AddRange(processedFoos.Except(foos, comparer));
您需要覆盖 Foo
中的 Equals
,或者实施 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()));
我认为你应该改变 select 不重复记录的方式:
processedFoos.Where(x => !foos.Any(y => y.FooId == x.FooId && y.FooField == x.FooField))
Except
和 Distinct
都有一个需要 IEqualityComparer
的重载。您可以实现一个来仅比较您需要的属性。
另一种方法是按 FooId 和 FooField 分组,然后从每组中取出第一个元素:
processFoos.GroupBy(foo => new {foo.FooId, foo.FooField})
.Select(g => g.First());