5

私はしばらく LINQ とラムダ式を使用してきましたが、機能のすべての側面にまだ完全に満足しているわけではありません。

そのため、最近プロジェクトに取り組んでいたときに、いくつかのプロパティに基づいてオブジェクトの個別のリストを取得する必要があり、このコードに出くわしました。それはうまくいきますが、グループ化のメカニズムを理解したいと思います。単純にコードを差し込んで問題から逃げるのは好きではありません。

とにかくコードは次のとおりです。

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

上記のコード サンプルでは、​​最初にプロパティでグループ化するように指示するラムダ式を呼び出しGroupByて渡していますvalue1。コードの 2 番目のセクションが混乱を引き起こしています。

key声明で言及value1していることは理解しています(key, group)が、起こっていることすべてにまだ頭を悩ませているわけではありません。

4

6 に答える 6

7

表現は何ですか

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

行う?

これにより、実行時にシーケンスを分析してグループのシーケンスlistを生成し、グループのシーケンスを新しいシーケンスに射影するクエリが作成されます。この場合、プロジェクションは各グループから最初のアイテムを取り出すことです。

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

2 番目のラムダ プロジェクトは、一連のキー付きグループから投影されます。selectグループのシーケンスを実行したかのようです。このクエリの最終的な効果は、結果のシーケンスの各要素がvalue1プロパティの異なる値を持つように、リストから一連の要素を選択することです。

ドキュメントは次のとおりです。

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

ドキュメントが明確でない場合は、喜んでドキュメント マネージャーに批判を伝えます。

このコードはgroup、ラムダの仮パラメーターとして使用します。group予約済みのキーワードではありませんか?

いいえ、groupコンテキストキーワードです。groupLINQ は C# 3.0 に追加されたため、識別子としてを使用する既存のプログラムが既に存在する可能性があります。groupこれらのプログラムは、 を予約済みキーワードにすると、再コンパイル時に壊れます。代わりにgroup、クエリ式のコンテキストでのみキーワードになります。クエリ式の外では、通常の識別子です。

それが通常の識別子であるという事実に注意を喚起したい場合、またはgroupクエリ式内で識別子を使用したい場合は、コンパイラに「これをキーワードではなく識別子として扱う」ように指示することができます@。上記のコードを書いていたら、

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

明確にするために。

C# には他のコンテキスト キーワードがありますか?

はい。私はそれらすべてをここに文書化しました:

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

于 2013-02-28T15:59:02.690 に答える
4

これを次のリストに単純化し、intこのリストで次のように区別する方法を説明したいと思いますGroupBy

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}

あなたのケースはこれと似ています。

于 2013-02-28T16:04:29.877 に答える
2

メソッドのこのオーバーロードを使用します。Enumerable.GroupBy

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

MSDNに記載されているように、これは次のとおりです。

指定されたキー セレクター関数に従ってシーケンスの要素をグループ化し、各グループとそのキーから結果値を作成します。

したがって、一連のグループ (つまり ) を返す他のオーバーロードとは異なりIEnumerable<IGrouping<TK, TS>>、このオーバーロードでは、各グループを選択した の 1 つのインスタンスに射影できますTResult

GroupBy基本的なオーバーロードとSelect:を使用して同じ結果を得ることができることに注意してください。

var listDistinct = list
    .GroupBy(i => i.value1)
    .Select(g => g.First())
    .ToList();
于 2013-02-28T16:01:22.307 に答える
1
(key, group) => group.First()

First()各グループ内の要素を取得しているだけです。

そのラムダ式内には、そのグループ(あなたの例では)をkey作成するために使用されたキーがあり、それを持つすべての要素があります。value1groupIEnumerable<T>key

于 2013-02-28T15:57:17.897 に答える
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
    }
}
于 2013-02-28T16:10:49.617 に答える
0

と同等です

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

元のコードの部分i => i.value1key selectorです。このコードでは、 は単純にgroup 要素 by keyi.valueの構文にあります。

(key, group) => group.First()元のコードの部分は結果セレクターのデリゲートです。このコードでは、from ... selectというより意味論的な構文で記述されています。is ここggroup元のコードがあります。

于 2013-02-28T16:15:30.413 に答える