てくメモ

trivial な notes

【C#】IEnumerable<T>.ToXXX 系の確認

以下の記事で、IEnumerable<T>.ToArrayの中身を確認した。
【C#】IEnumerable<T>.ToArray の中身を確認 - てくメモ

この機会に、それ以外のコレクションにするメソッド(ToListToDictionaryToHashSetToLookup)を確認しておく。

ちなみに、変わったことはなかったので本当に確認。

ToArray v.s. ToList

どっちを使うのがよいの? というような感じで並べられることがある。

しかし、ToListは(IIListProvider<TSource>を用いて最適化が図られているが基本的にはList<T>コンストラクタのショートハンドなので、単純に配列とリストのどっちが適するかで決めればよいと思う。
参考:Source BrowserToList<TSource>拡張メソッド)


少し踏み込めば、リストは配列より高級なので、リスト操作を必要としなければ常にToArrayでよい。

ToDictionaryToHashSetToLookup

ToDictionaryはシーケンスを辞書にする。

実質、シーケンスを渡すDictionary<TKey, TValue>コンストラクタのショートハンド。
参考:Source BrowserToDictionary<TKey, TValue>拡張メソッド)

普通に操作する場合もそうであるように、重複要素があると例外が飛ぶ。

IEnumerable<int> source = new int[] { 1, 2, 3, 1 };
var dic = source.ToDictionary(v => v); // ❌ ArgumentException


ただ、辞書が浮かんでも、実際にしたいのはToHashSetあるいはToLookupという場合がある。

ユニークな要素のコレクションをつくりたい場合は前者、重複ありのキー-要素コレクションをつくりたい場合は後者を使う。


ToHashSetHashSet<T>コンストラクタのショートハンド。
参考:Source BrowserToHashSet<TSource>拡張メソッド)

var set = source.ToHashSet();
Console.WriteLine(set.ToListString()); // ToListString という [a, b, c...] というような文字列とする拡張メソッドがあるものとする
// [1, 2, 3]

HashSet<T>.Addが例外を出さないのと同様、これも例外は飛ばない。

リストのときと同じくLINQ固有の話ではないけれど、ユニークな要素のコレクションで順序が重要でなければHashSet<T>を使う。


ToLookupは、キーで要素をグルーピングしたコレクションを生成する。
参考:Source BrowserToLookup<TSource, TKey>拡張メソッド

百聞は一見に如かず。

var lookup = source.ToLookup(v => v);
foreach ( var group in lookup)
{
    Console.WriteLine($"Key={group.Key}, Items={group.ToListString()}");
}
// Key=1, Items=[1, 1]
// Key=2, Items=[2]
// Key=3, Items=[3]


これに関しては既存コレクション生成のショートハンドではなく、引き出しに入れておきたい。

ちなみに、このメソッドで返ってくるILookup、そしてそれが内容として持つIGroupingは、実装クラスがinternalであり、実装の流用ができない。(😥)


個人的なまとめ

  • 基本を置くのはToArray
  • リスト、辞書、セットが使いたければそれぞれの ToXXX
    • これらに関しては LINQ というより単にどの構造を使うかというお話
  • ToLookupは頭に入れておく