81

との違いを明確にするのに苦労してきましたが、ILookup<TKey, TVal>IGrouping<TKey, TVal>正しく理解できているかどうか興味があります。LINQは、拡張メソッドIGroupingを提供しながら、アイテムのシーケンスを生成することで問題を悪化させました。ToLookupですから、よく見るまでは同じように感じました。

var q1 = 
    from n in N
    group n by n.MyKey into g
    select g;
// q1 is IEnumerable<IGrouping<TKey, TVal>>

これは次と同等です:

var q2 = N.GroupBy(n => n.MyKey, n => n);
// q2 is IEnumerable<IGrouping<TKey, TVal>>

これはよく似ています:

var q3 = N.ToLookup(n => n.MyKey, n => n);
// q3 is ILookup<TKey, TVal>

私は次の例えで正しいですか?

  1. AnIGrouping<TKey, TVal>は単一のグループ(つまり、キー付きシーケンス)でKeyValuePair<TKey, TVal>あり、値が実際には(単一の要素ではなく)要素のシーケンスである場合に類似しています。
  2. AnIEnumerable<IGrouping<TKey, TVal>>はそれらのシーケンスです(繰り返し処理したときに得られるものと同様です)IDictionary<TKey, TVal>
  3. Anは、値が実際には要素のシーケンスであるILookup<TKey, TVal>aに似ていますIDictionary<TKey, TVal>
4

3 に答える 3

78

はい、それらはすべて正しいです。

またILookup<TKey, TValue>、拡張IEnumerable<IGrouping<TKey, TValue>>機能により、すべてのキーとコレクションのペアを反復処理したり、特定のキーを検索するだけでなく(またはその代わりに)実行したりできます。

私は基本的にのように考えILookup<TKey,TValue>ていIDictionary<TKey, IEnumerable<TValue>>ます。

ToLookupこれは「今すぐ実行」操作(即時実行)であるのに対し、aGroupByは延期されることに注意してください。たまたま、「pull LINQ」が機能する方法ではIGrouping、の結果からsをプルし始めるGroupByと、とにかくすべてのデータを読み取る必要があります(途中でグループを切り替えることができないため)が、他の実装ではストリーミング結果を生成できる。(これはプッシュLINQで行われます。LINQtoEventsは同じであると思います。)

于 2009-08-26T21:21:55.837 に答える
8

ILookupとIDictionaryには、もう1つの重要な違いがあります。前者は、データを変更する方法がないという意味で不変性を強制します(コンシューマーが明示的なキャストを実行する場合を除く)。対照的に、IDictionaryには、データを変更できる「追加」のようなメソッドがあります。したがって、関数型プログラミングや並列プログラミングの観点からは、ILookupの方が優れています。(グループではなく、キーに1つの値のみを割り当てるバージョンのILookupもあったらいいのにと思います。)

(ところで、IEnumerableとIListの関係は、ILookupとIDictionaryの関係にいくぶん似ていることを指摘する価値があるようです。前者は不変ですが、後者は不変です。)

于 2013-06-05T16:00:57.320 に答える
8

GroupByこれを除いToLookUpてほぼ同じ機能を持っています:リファレンス

GroupBy:GroupBy演算子は、いくつかのキー値に基づいて要素のグループを返します。各グループはIGroupingオブジェクトで表されます。

ToLookup:ToLookupはGroupByと同じです。唯一の違いは、GroupByの実行が延期されるのに対し、ToLookupの実行は即時であるということです。

サンプルコードを使用して違いを明確にしましょう。Personモデルを表すクラスがあるとします。

class Personnel
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public int Level { get; set; }
}

その後、personnels以下のリストを定義します。

 var personnels = new List<Personnel>
    {
        new Personnel { Id = 1, FullName = "P1", Level = 1 },
        new Personnel { Id = 2, FullName = "P2", Level = 2 },
        new Personnel { Id = 3, FullName = "P3", Level = 1 },
        new Personnel { Id = 4, FullName = "P4", Level = 1 },
        new Personnel { Id = 5, FullName = "P5", Level =2 },
        new Personnel { Id = 6, FullName = "P6", Level = 2 },
        new Personnel { Id = 7, FullName = "P7", Level = 2 }
    };

次に、レベルごとにグループ化する必要がありpersonnelsます。ここでは2つのアプローチがあります。GroupByまたはを使用しToLookUpます。前に述べたように、を使用GroupByすると、遅延実行が使用されます。つまり、コレクションを反復処理すると、次のアイテムが要求されるまで計算される場合とされない場合があります。

 var groups = personnels.GroupBy(p => p.Level);
    personnels.RemoveAll(p => p.Level == 1);
    foreach (var product in groups)
    {
        Console.WriteLine(product.Key);
        foreach (var item in product)
            Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
    }

上記のコードでは、最初にをグループ化しましたpersonnelsが、それを繰り返す前に、いくつかを削除しましたpersonnels。は遅延実行を使用するため、グループ化はここでポイントでGroupBy計算されるため、最終結果には削除されたアイテムは含まれません。foreach

出力:

2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2

しかし、上記のコードを次のように書き直した場合:(コードは前のコードと同じですが、GroupByが置き換えられていることに注意してくださいToLookUp

 var groups = personnels.ToLookup(p => p.Level);
    personnels.RemoveAll(p => p.Level == 1);
    foreach (var product in groups)
    {
        Console.WriteLine(product.Key);
        foreach (var item in product)
            Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
    }

ToLookUp即時実行を使用する場合、メソッドを呼び出すと結果が生成され、グループが適用されることを意味します。したがって、反復の前にToLookUpアイテムを削除しても、最終結果には影響しません。personnels

出力:

1
1 >>> P1 >>> 1
3 >>> P3 >>> 1
4 >>> P4 >>> 1
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2

注:両方GroupByToLookUpも異なるタイプを返します。

ToLookUpの代わりにToDictionaryを使用することもできますが、これに注意する必要があります:(参照

ToLookup()の使用法は、ToDictionary()の使用法と非常によく似ており、どちらもキーセレクター、値セレクター、および比較子を指定できます。主な違いは、ToLookup()は重複キーを許可(および期待)するのに対し、ToDictionary()は許可しないことです。

于 2018-08-08T09:15:12.760 に答える