3
public class Item
{
    public int Id {get; set;}
    public bool Selected {get; set;}
}

List<Item> itemList = new List<Item>(){ /* fill with items */ };

我需要创建一个满足以下条件的项目列表。从itemList,我需要对项目进行分组Id,然后从每个组中选择一个项目。所选项目必须是其中之一Selected == true。如果组中没有项目被选中,那么任何项目都可以被选中,没关系,但必须选择一个。

基于这个问题: How to get distinct instance from a list by Lambda or LINQ

我能够将以下内容放在一起,这似乎可行:

var distinctList = itemList.GroupBy(x => x.Id, 
    (key, group) => group.Any(x => x.Selected) ? 
        group.First(x => x.Selected) : group.First());

有没有更有效或更简单的方法来实现这一目标?我试过FirstOrDefault()但似乎无法让它做我需要的。我对上述代码效率的担忧是对 Any() 的调用。

4

3 回答 3

3

您确实可以使用FirstOrDefault扩展方法,但使用带有谓词的版本,并将其与合并运算符 ( ??)结合起来,如下所示(我在这里使用了查询语法以使其更容易):

var distinctList =
    from item in itemList
    group item by item.Id into g
    select g.FirstOrDefault(i => i.Selected) ?? g.First();

使用 in 中的谓词FirstOrDefault,您将选择Selected属性为真的第一个项目。如果没有,那么假设您的类型是引用类型(这对于使用 很重要FirstOrDefault),它将返回null.

如果返回 null ,那么您将只返回组中的第一个项目(通过调用First),因为可以返回任何项目,并且如果没有First项目,组就不能存在(因此始终保证调用成功)。

基本上,您将选择器应用于分组结果,而不是分组时。

于 2012-04-16T20:59:31.763 回答
0

bool您可以使用实现IComparable<bool>,true大于的事实false

var distinctList = itemList.GroupBy(x => x.Id,  
    (key, group) => group.OrderByDescending(x => x.IsSelected).First()); 

但是,这需要对整个组进行枚举和排序,所以如果你坚持你的方法,你的表现会更好。

对于具有选定项目的组,您的方法需要将列表迭代两次,直到第一个选定项目的位置。您可以像这样删除该重复项:

var distinctList = itemList.GroupBy(x => x.Id,  
    (key, group) => group.FirstOrDefault(x => x.Selected) ?? group.First()); 
于 2012-04-16T21:06:06.930 回答
0

更简单的答案在这里

您可以使用

groupedSource.SelectMany(group => group).Single(item => item.Id == 1)
于 2014-08-01T20:19:56.800 回答