告诉LINQ区分要返回的项目

时间:2010-03-30 13:24:46

标签: c# linq .net-3.5 c#-3.0 ienumerable

我理解如何在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。

5 个答案:

答案 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()用于查找不同的元素。如果您担心返回哪个元素......那么显然它们并不是真正相同(因此并不明显),并且您的设计存在缺陷。