C# ジェネリックコレクションの使い分け
.NET には多数のジェネリックコレクションが用意されています。それぞれ特性が異なるため、用途に応じて使い分けることが重要です。
主要なジェネリックコレクション
List<T>
可変長の配列。インデックスによる高速アクセス。最も汎用的。
Dictionary<TKey, TValue>
キーと値のペア。キーによる高速検索。
HashSet<T>
重複のない要素の集合。存在確認が高速。
Queue<T>
先入れ先出し(FIFO)。順番に処理するタスク向け。
Stack<T>
後入れ先出し(LIFO)。履歴管理や再帰の代替に。
LinkedList<T>
双方向リンクリスト。途中への挿入・削除が高速。
List<T> vs 配列
List<T> は可変長、配列は固定長という違いがあります。
// 配列:サイズ固定
int[] array = new int[3];
// array に要素を追加することはできない
// List<T>:サイズ可変
var list = new List<int> { 1, 2, 3 };
list.Add(4); // 要素の追加が可能Dictionary<TKey, TValue> の使いどころ
キーから値を高速に検索したい場合に最適です。
var scores = new Dictionary<string, int>
{
["Alice"] = 95,
["Bob"] = 87,
["Charlie"] = 92
};
// O(1) で検索
if (scores.TryGetValue("Alice", out int score))
{
Console.WriteLine($"Alice: {score}点");
}HashSet<T> vs List<T>
重複を許さない、または存在確認が多い場合は HashSet<T> が適しています。
List<T> の Contains
O(n) で要素を順番に探す
HashSet<T> の Contains
O(1) でハッシュにより即座に判定
var hashSet = new HashSet<int> { 1, 2, 3, 4, 5 };
var list = new List<int> { 1, 2, 3, 4, 5 };
// 大量のデータで Contains を繰り返す場合、HashSet が圧倒的に速い
bool existsInSet = hashSet.Contains(3); // 高速
bool existsInList = list.Contains(3); // 要素数に比例Queue<T> と Stack<T>
データの処理順序が重要な場合に使います。
// Queue:先に入れたものから出る
var queue = new Queue<string>();
queue.Enqueue("First");
queue.Enqueue("Second");
Console.WriteLine(queue.Dequeue()); // First
// Stack:後に入れたものから出る
var stack = new Stack<string>();
stack.Push("First");
stack.Push("Second");
Console.WriteLine(stack.Pop()); // Second選択の指針
// インデックスアクセスが必要 → List<T>
var items = new List<string>();
string first = items[0];
// キーで検索したい → Dictionary
var dict = new Dictionary<string, User>();
User user = dict["user123"];
// 重複を排除したい → HashSet
var unique = new HashSet<int>(duplicatedList);
// 順番に処理したい → Queue
var tasks = new Queue<Task>();
// 直前の状態に戻りたい → Stack
var history = new Stack<State>();パフォーマンス比較
| 操作 | List<T> | Dictionary | HashSet |
|---|---|---|---|
| インデックスアクセス | O(1) | - | - |
| 末尾への追加 | O(1)* | O(1)* | O(1)* |
| 検索 | O(n) | O(1) | O(1) |
| 削除(値指定) | O(n) | O(1) | O(1) |
* 平均的なケース。容量拡張時は O(n)。
用途に適したコレクションを選ぶことで、コードの可読性とパフォーマンスの両方を向上させられます。