2012-04-16 55 views
2
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。如果沒有選擇組中的項目,則可以選擇任何項目,這並不重要,但必須選擇一個項目。基於這個問題使用LINQ從IGrouping中選擇特定元素

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

是不是很簡單的嗎?添加一些額外的換行符和/或刪除一些縮進,以便更好地適應屏幕,對我來說看起來很好。 – Servy 2012-04-16 20:48:51

+0

@Servy - 我不明白倒票嗎?下面的答案比我上面的例子更簡單,更高效。這就是我問這個問題的原因。 – 2012-04-17 01:08:30

回答

3

你的確可以使用FirstOrDefault extension method,但使用version that takes a predicate,並與coalesce operator (??)像這樣結合起來(我這裏使用的查詢語法,使之更容易):在FirstOrDefault

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

使用謂詞,您正在挑選Selected屬性爲true的第一個項目。如果沒有,那麼假設你的類型是一個引用類型(這對於與FirstOrDefault一起使用非常重要),它將返回null

如果返回null,那麼你就只返回的第一個項目組中(通過調用First),因爲任何項目可以返回,並在其中一組不能存在沒有項目(所以撥打First始終保證成功)。

基本上,你申請一個選擇到結果分組,不分組。

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

答案更簡單here

您可以使用

groupedSource.SelectMany(group => group).Single(item => item.Id == 1)