2013-02-28 11 views
5

私はしばらくLINQとLambda Expressionsを使っていましたが、私はまだこの機能のあらゆる面を完全に満足させていません。このラムダグループ機能について説明できますか?

私は最近プロジェクトで作業していましたが、いくつかのプロパティに基づいてオブジェクトの別個のリストを取得する必要がありました。このコードを実行しました。それはうまくいっていますが、私はグループ化の仕組みを理解したいと思います。私はそれを助けることができれば、単にコードを差し込み、問題から遠ざけるのが好きではありません。

とにかくコードは次のとおりです。上記のコードサンプルで

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

、最初GroupByを呼び出し、それをプロパティvalue1によってグループにそれを伝えるラムダ式を渡しています。コードの2番目のセクションは混乱を引き起こしています。

key(key, group)の文でvalue1を参照していることを理解していますが、私はまだ行われているすべてのことを頭で囲んでいません。

答えて

7

これは、実行されると、グループのシーケンスを生成するシーケンスlistを分析し、クエリを作成し、プロジェクト新しいシーケンスにグループの配列。この場合、投影は各グループから最初の項目を取り出すことです。

最初のラムダは、グループを構成する「キー」を選択します。この場合、同じvalue1プロパティを持つリスト内のすべての項目がグループに入れられます。彼らが共有する価値は、グループの「鍵」になります。

2番目のラムダは、キー付きグループのシーケンスから投影されます。それはあなたがグループの順序でselectをやったかのようです。このクエリの正味の効果は、結果のシーケンスの各要素がvalue1プロパティの異なる値を持つように、リストから要素のセットを選択することです。

ドキュメント

はここにある:ドキュメントが明確ではありません

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

場合、私はドキュメントマネージャへの批判に沿って通過することが幸せです。

このコードでは、ラムダの仮パラメータとしてgroupを使用しています。 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。ドキュメントはかなり明確です。上記のシナリオで使用されている「グループ」は予約語ではなく、そのラムダの説明的な名前を渡すことができます。それはかなり助けになる - 私はこのグループがこの操作のための予約語であると思っていたが、それ以外の場合は何が起きているのかが少しはっきりしていると考えていた。 – elucid8

+0

また、あなたは上司です。 – elucid8

+0

@ elucid8:私はあなたの2番目の質問に答えるために私の答えを更新します。 –

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

各グループ内でFirst()という要素を使用しているだけです。そのラムダ式key

は、そのグループを作成するために使用されたキー(あなたの例ではvalue1)であるとgroupkeyことがあるすべての要素を持つIEnumerable<T>です。表現

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

は何をするん

2

それはEnumerable.GroupBy方法のthis overload使用しています:

グループの要素を:MSDN上に述べたように、

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

をシーケンスを指定されたキーセレクタ関数に従って選択し、各グループおよびそのキーから結果値を作成する。

ので、グループの束(すなわちIEnumerable<IGrouping<TK, TS>>)を返しother overloadsとは異なり、このオーバーロードは、あなたの好みのTResultの単一のインスタンスに各グループを投影することができます。

注あなたは、基本的なGroupBy過負荷およびSelect使用して同じ結果を得ることができること:

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

を私はintのリストにこれを簡素化したいとGroupByを使用して、このリストの中に異なるを行う方法:

:あなたは x => xGroupByを呼び出す場合

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

、あなたはタイプの3グループを取得します

IEnumerable<IEnumerable<int>> 

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

各グループのキーは、次のとおりです。

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

だから、最終的な結果は次のとおりです:group.First()を呼び出すときに1、2、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'メソッドに関するものです –

+0

@PhilippM:思考をクリアするために、わかりやすく簡潔な* GroupBy *構文をLINQクエリの読みやすく冗長な構文に変更することにしました。物事を明確にするために。 –

0

をそれはあなたの元のコードに一部i => i.value1

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

にequvilantだがキーセレクターです。このコードでは、グループ要素のi.valueであり、キーです。

元のコードの(key, group) => group.First()の部分は、代理人結果セレクタです。このコードでは、より意味のある構文で書かれています...を選択してください。ここにgは元のコードでgroupです。

関連する問題