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()的调用。
答案 0 :(得分:3)
您确实可以使用FirstOrDefault
extension method,但使用version that takes a predicate,并将其与coalesce operator (??
)结合使用(我在此处使用了查询语法,以便更轻松):< / p>
var distinctList =
from item in itemList
group item by item.Id into g
select g.FirstOrDefault(i => i.Selected) ?? g.First();
使用FirstOrDefault
中的谓词,您将选择Selected
属性为true的第一个项目。如果没有,那么假设您的类型是引用类型(这对于使用FirstOrDefault
来说很重要),它将返回null
。
如果返回null,那么您只需返回组中的第一个项目(通过调用First
),因为任何项目都可以返回,并且组不能存在没有< / em>中的项目(因此始终保证对First
的调用成功)。
基本上,您将选择器应用于分组的结果,而不是分组。
答案 1 :(得分: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());
答案 2 :(得分:0)