我理解如何在IEnumerable上做一个Distinct(),并且我必须为更高级的东西创建一个IEqualityComparer,但有没有一种方法可以告诉哪个重复的项目要返回?
例如,假设你有List<T>
List<MyClass> test = new List<MyClass>();
test.Add(new MyClass {ID = 1, InnerID = 4});
test.Add(new MyClass {ID = 2, InnerID = 4});
test.Add(new MyClass {ID = 3, InnerID = 14});
test.Add(new MyClass {ID = 4, InnerID = 14});
然后你做:
var distinctItems = test.Distinct(new DistinctItemComparer());
class DistinctItemComparer : IEqualityComparer<MyClass> {
public bool Equals(MyClass x, MyClass y) {
return x.InnerID == y.InnerID;;
}
public int GetHashCode(MyClassobj) {
return obj.InnerID.GetHasCode();
}
}
此代码将返回ID为1和3的类。有没有办法返回ID匹配2&amp; 4。
答案 0 :(得分:4)
我不相信它实际上是保证,但我会非常惊讶地看到Distinct
的行为按照它们在源序列中出现的顺序从返回的项目发生变化。
因此,如果您想要特定的项目,您应该以这种方式订购源序列。例如:
items.OrderByDescending(x => x.Id)
.Distinct(new DistinctItemComparer());
请注意,使用Distinct与自定义比较器的一种替代方法是使用MoreLINQ中的DistinctBy
:
items.OrderByDescending(x => x.Id)
.DistinctBy(x => x.InnerId);
虽然您不能保证从Distinct
订购的正常LINQ to Objects不会改变,但我很乐意为MoreLINQ添加保证:)(这是唯一合理的订购,无论如何,说实话。)
另一种替代方法是使用GroupBy
代替 - 然后对于每个内部ID,您可以所有匹配项目,然后从那里开始。
答案 1 :(得分:3)
您不希望区别 - 您希望根据ID对项目进行分组并为其选择“最大”元素:
var distinctItems = test.Distinct(new DistinctItemComparer());
var otherItems = test.GroupBy(a => a.InnerID, (innerID, values) => values.OrderBy(b => b.ID).Last());
var l1 = distinctItems.ToList();
var l2 = otherItems.ToList();
l1 =您当前的列表 l2 =您想要的清单
答案 2 :(得分:2)
这听起来不像是Distinct
的工作,这听起来像是Where
的工作。您希望过滤您案例中的序列:
var ids = new[] { 2, 4 };
var newSeq = test.Where(m => ids.Contains(m.ID));
答案 3 :(得分:2)
如果您想使用您使用的比较选择一组被认为相等的元素,那么您可以使用group by
:
var q = from t in tests
group t by t.InnerID into g
select g.First(...);
在select
子句中,您将获得相等的元素集合,您可以选择所需的一个特定元素(例如,使用First(...)
)。实际上您不需要在末尾添加Distinct
,因为您已经为每个组选择了一个元素。
答案 4 :(得分:1)
不,没有办法。
Distinct()
用于查找不同的元素。如果您担心返回哪个元素......那么显然它们并不是真正相同(因此并不明显),并且您的设计存在缺陷。