2013-02-28 112 views
5

我一直在使用LINQ和Lambda Expressions一段時間,但我仍然不完全熟悉該功能的各個方面。你能解釋一下這個lambda分組函數嗎?

所以,當我最近在一個項目上工作時,我需要根據一些屬性獲得一個清晰的對象列表,並且我跑過了這段代碼。它的工作原理,我很好,但我想了解分組機制。我不喜歡簡單地插入代碼並逃避問題,只要我能幫上忙。

反正的代碼是:

var listDistinct 
    =list.GroupBy(
     i => i.value1, 
     (key, group) => group.First() 
    ).ToList(); 

在上面的代碼示例中,你首先調用GroupBy並使其lambda表達式告訴它組由屬性value1。代碼的第二部分引起了混淆。

據我所知,key(key, group)聲明中引用value1,但我仍然沒有對發生的所有事情進行包袱。

回答

7

什麼表達

list.GroupBy(
    i => i.value1, 
    (key, group) => group.First()) 

嗎?

這產生一個查詢被執行時,分析該序列list以產生組的序列,然後項目組的序列到一個新的序列。在這種情況下,投影是從每個組中取出第一項。

第一個lambda選擇構建組的「關鍵」。在這種情況下,將具有相同value1屬性的列表中的所有項目放在一個組中。他們分享的價值成爲該組織的「關鍵」。

第二個lambda項目來自鍵控組的序列;就好像你在組序列上做了select。此查詢的最終效果是從列表中選擇一組元素,以使得結果序列的每個元素具有不同的value1屬性值。

的文檔是在這裏:

http://msdn.microsoft.com/en-us/library/bb549393.aspx

如果文檔不清晰,我很高興地沿着批評的文檔管理員通過。

該代碼使用group作爲lambda的形式參數。是不是group保留關鍵字?

不,group上下文關鍵字。 LINQ被添加到C#3.0中,因此可能已經存在使用group作爲標識符的程序。如果group已成爲保留關鍵字,這些程序將在重新編譯時被破壞。相反,group僅在查詢表達式的上下文中是關鍵字。在查詢表達式之外,它是一個普通的標識符。

如果您想引起人們對它是普通標識符這一事實的關注,或者想要在查詢表達式中使用標識符group,則可以告訴編譯器「將其視爲標識符而不是關鍵字」通過與@進行預處理。如果我寫上面的代碼我會說

list.GroupBy(
    i => i.value1, 
    (key, @group) => @group.First()) 

說清楚。

C#中是否還有其他上下文關鍵字?

是的。我已經證明他們都在這裏:

http://ericlippert.com/2009/05/11/reserved-and-contextual-keywords/

+0

謝謝Eric。文件相當清楚。我是否理解上述場景中使用的「組」不是保留字,我可以爲該lambda傳入更多描述性名稱?這很有幫助 - 我絆倒了,認爲這個組織是這個操作的保留字,但是知道其他情況會使它對於發生的事情更加明顯。 – elucid8 2013-02-28 16:04:26

+0

另外,您是老闆,先生。 – elucid8 2013-02-28 16:14:42

+0

@ elucid8:我會更新我的答案以解決您的第二個問題。 – 2013-02-28 16:27:37

1
(key, group) => group.First() 

它只是把每個組內的First()元素。

在這一lambda表達式key是用於創建該組密鑰(value1在你的例子)和groupIEnumerable<T>連接有該key所有元素。

2

它使用Enumerable.GroupBy方法this overload

public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(
    this IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector, 
    Func<TKey, IEnumerable<TSource>, TResult> resultSelector 
) 

其中,作爲MSDN說:

組的元素按照指定的鍵選擇器功能進行排序,並從每個組及其鍵創建結果值。

因此,與other overloads其返回一串組(即IEnumerable<IGrouping<TK, TS>>),這種過載可以讓你每一組投影到您所選擇的TResult的單個實例。

需要注意的是,你可以使用基本GroupBy超載得到同樣的結果和Select

var listDistinct = list 
    .GroupBy(i => i.value1) 
    .Select(g => g.First()) 
    .ToList(); 
4

我想用GroupBy簡化這個到int以及如何列表做此列表不同:

var list = new[] {1, 2, 3, 1, 2, 2, 3}; 

如果調用GroupByx => x,您將獲得3組類型:

IEnumerable<IEnumerable<int>> 

{{1,1},{2,2,2},{3,3}} 

各組的主要有:1,2,3,然後調用group.First()時,就意味着你會得到每組的第一個項目:

{1,1}: -> 1. 
{2,2,2}: -> 2 
{3,3} -> 3 

所以最後的結果是:{1, 2, 3}

您的情況與此類似。

0

下面的自描述的例子應該幫助您瞭解分組:

class Item 
{ 
    public int Value { get; set; } 
    public string Text { get; set; } 
} 

static class Program 
{ 
    static void Main() 
    { 
     // Create some items 
     var item1 = new Item {Value = 0, Text = "a"}; 
     var item2 = new Item {Value = 0, Text = "b"}; 
     var item3 = new Item {Value = 1, Text = "c"}; 
     var item4 = new Item {Value = 1, Text = "d"}; 
     var item5 = new Item {Value = 2, Text = "e"}; 

     // Add items to the list 
     var itemList = new List<Item>(new[] {item1, item2, item3, item4, item5}); 

     // Split items into groups by their Value 
     // Result contains three groups. 
     // Each group has a distinct groupedItems.Key --> {0, 1, 2} 
     // Each key contains a collection of remaining elements: {0 --> a, b} {1 --> c, d} {2 --> e} 
     var groupedItemsByValue = from item in itemList 
            group item by item.Value 
            into groupedItems 
            select groupedItems; 

     // Take first element from each group: {0 --> a} {1 --> c} {2 --> e} 
     var firstTextsOfEachGroup = from groupedItems in groupedItemsByValue 
            select groupedItems.First(); 

     // The final result 
     var distinctTexts = firstTextsOfEachGroup.ToList(); // Contains items where Text is: a, c, e 
    } 
} 
+0

不錯的例子,但這個問題是關於lamda'GroupBy'方法 – 2013-02-28 16:15:26

+0

@PhilippM:爲了清除這個想法,我決定將簡短易懂的* GroupBy *語法改成可讀和詳細的LINQ查詢語法。只是爲了說清楚。 – 2013-02-28 16:19:18

0

這是equvilant到

var listDistinct=(
    from i in list 
    group i by i.value1 into g 
    select g.First() 
    ).ToList(); 

的部分i => i.value1在原始代碼是鍵選擇。在這個代碼中,簡單地用i.value的語法組成組元素

原始代碼中的部分(key, group) => group.First()是結果選擇器的代表。在這個代碼中,它是用更多語義語法編寫的from ... select。在這裏ggroup在原來的代碼。

相關問題