public class Item
{
public int Id {get; set;}
public bool Selected {get; set;}
}
List<Item> itemList = new List<Item>(){ /* fill with items */ };
I need to create a list of Items that meet the following criteria. From itemList, I need to group the items by Id and then choose a single item from each group. The chosen item must be one in which Selected == true. If no item in the group is selected, then any item can be chosen, it doesn’t matter, but one must be chosen.
Based on this question:
How to get distinct instance from a list by Lambda or LINQ
I was able to put together the following, which seems to work:
var distinctList = itemList.GroupBy(x => x.Id,
(key, group) => group.Any(x => x.Selected) ?
group.First(x => x.Selected) : group.First());
Is there a more efficient or simpler way to achieve this? I tried FirstOrDefault() but couldn’t seem to make it do what I needed. My concern with the efficiency in the above code, is the call to Any().
You can indeed use the
FirstOrDefaultextension method, but use the version that takes a predicate, and combine it with the coalesce operator (??) like so (I’ve used query syntax here to make it easier):Using the predicate in
FirstOrDefault, you are picking the first item where theSelectedproperty is true. If there is none, then assuming your type is a reference type (and this is important this to work withFirstOrDefault), it will returnnull.If null is returned, then you’ll just return the first item in the group (through the call to
First), since any item can be returned and a group can’t exist without items in it (so the call toFirstis always guaranteed to succeed).Basically, you are applying a selector to the result of the grouping, not while grouping.