Tell LINQ Distinct which item to return

落花浮王杯 提交于 2020-01-04 02:34:25

问题


I understand how to do a Distinct() on a IEnumerable and that I have to create an IEqualityComparer for more advanced stuff however is there a way in which you can tell which duplicated item to return?

For example say you have a 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});

You then do:

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();
    }
}

This code will return the classes with ID 1 and 3. Is there a way to return the ID matches 2 & 4.


回答1:


You don't want distinct then - you want to group your items and select the "maximum" element for them, based on 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 = your current list l2 = your desired list




回答2:


I don't believe it's actually guaranteed, but I'd be very surprised to see the behaviour of Distinct change from returning items in the order they occur in the source sequence.

So, if you want particular items, you should order your source sequence that way. For example:

items.OrderByDescending(x => x.Id)
     .Distinct(new DistinctItemComparer());

Note that one alternative to using Distinct with a custom comparer is to use DistinctBy from MoreLINQ:

items.OrderByDescending(x => x.Id)
     .DistinctBy(x => x.InnerId);

Although you can't guarantee that the normal LINQ to Objects ordering from Distinct won't change, I'd be happy to add a guarantee to MoreLINQ :) (It's the only ordering that is sensible anyway, to be honest.)

Yet another alternative would be to use GroupBy instead - then for each inner ID you can get all the matching items, and go from there.




回答3:


This doesn't sound like a job for Distinct, this sounds like a job for Where. You want to filter the sequence in your case:

var ids = new[] { 2, 4 };
var newSeq = test.Where(m => ids.Contains(m.ID));



回答4:


If you want to select one particular of the group of elements that are considered equal using the comparison you use, then you can use group by:

 var q = from t in tests
         group t by t.InnerID into g
         select g.First(...);

In the select clause, you'll get a collection of elements that are equal and you can select the one specific element you need (e.g. using First(...)). You actually don't need to add Distinct to the end, because you're already selecting only a single element for each of the groups.




回答5:


No, there's no way.

Distinct() is used to find distinct elements. If you're worried about which element to return...then obviously they are not truly identical (and therefore not distinct) and you have a flaw in your design.



来源:https://stackoverflow.com/questions/2545493/tell-linq-distinct-which-item-to-return

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!