C# Listの使い方を基礎から解説|初期化・追加・削除・検索・ソートまでわかる入門ガイド
はじめに
C#で複数のデータを扱うときによく使われるのがList<T>です。List<T>は、要素数をあとから増やしたり減らしたりできるコレクションで、実務のC#開発でも非常に頻繁に登場します。
たとえば、ユーザー名の一覧、商品データの一覧、検索結果、スコアの集合など、同じ種類のデータをまとめて管理したい場面でListは便利です。
この記事では、C# Listの基本から、初期化、追加、削除、検索、ソート、LINQとの組み合わせ、注意点、実践サンプルまでを入門者向けに解説します。
1. C#のListとは?配列との違いと使う場面
1-1. List<T>の基本概要
C#のList<T>は、同じ型のデータを順番に格納できるコレクションです。
Tには、int、string、double、独自クラスなど、扱いたいデータ型を指定します。
C#List<int> numbers = new List<int>();
List<string> names = new List<string>();
List<int>であれば整数の一覧、List<string>であれば文字列の一覧を管理できます。
List<T>は、要素の追加や削除が簡単にできるため、C#で可変長のデータを扱うときによく使われます。
1-2. 配列とListの違い
C#には、複数の値を扱う方法として配列もあります。
C#int[] numbers = new int[3];
配列は作成時に要素数を決める必要があります。一方、List<T>はあとから要素を追加したり削除したりできます。
C#List<int> numbers = new List<int>();
numbers.Add(10);
numbers.Add(20);
numbers.Add(30);
主な違いは次のとおりです。
| 項目 | 配列 | List |
|---|---|---|
| 要素数 | 基本的に固定 | 追加・削除できる |
| 宣言 | int[] | List<int> |
| 追加 | 直接はしにくい | Addで簡単 |
| 削除 | 直接はしにくい | Removeなどで簡単 |
| 実務での使いやすさ | 固定データ向き | 可変データ向き |
データ数が最初から決まっている場合は配列、あとから増減する可能性がある場合はList<T>が向いています。
1-3. Listを使うメリット・デメリット
List<T>を使うメリットは、扱いやすさです。要素の追加、削除、検索、並び替えなどのメソッドが用意されているため、少ないコードでデータを操作できます。
主なメリットは次のとおりです。
要素を簡単に追加できる
要素を簡単に削除できる
要素数を
Countで取得できるforeachで順番に処理しやすいLINQと組み合わせやすい
クラスや構造体の一覧管理にも使える
一方で、デメリットもあります。
配列より少しオーバーヘッドがある
大量データでは使い方によってパフォーマンスに影響が出る
インデックス範囲外アクセスに注意が必要
検索が多い場合は
Dictionaryのほうが向いていることがある
1-4. Listが向いているケース
List<T>は、要素数が変わる可能性があるデータに向いています。
たとえば、次のようなケースです。
ユーザー一覧を管理する
商品一覧を管理する
入力された値を順番に保存する
検索結果を一時的に保持する
条件に一致するデータだけを抽出する
APIから取得したデータを格納する
C#でアプリケーションを作る場合、List<T>は基本中の基本といえるコレクションです。
2. C#でListを使うための基本準備
2-1. Listを使うために必要な名前空間
List<T>を使うには、通常、ファイルの先頭に次の名前空間を追加します。
C#using System.Collections.Generic;
たとえば、次のように書きます。
C#using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> names = new List<string>();
names.Add("田中");
Console.WriteLine(names[0]);
}
}
System.Collections.Genericには、List<T>、Dictionary<TKey, TValue>、HashSet<T>など、ジェネリックコレクションが含まれています。
2-2. List<T>の「T」とジェネリックの考え方
List<T>のTは、型を表します。
たとえば、整数を扱うならList<int>、文字列を扱うならList<string>と書きます。
C#List<int> scores = new List<int>();
List<string> fruits = new List<string>();
このように、扱う型を指定して使う仕組みをジェネリックと呼びます。
ジェネリックを使うことで、型安全にデータを扱えます。List<int>には整数だけ、List<string>には文字列だけを入れることができます。
C#List<int> numbers = new List<int>();
numbers.Add(10);
// numbers.Add("abc"); // エラー
誤った型のデータを入れようとするとコンパイルエラーになるため、バグを防ぎやすくなります。
2-3. Listで扱える主なデータ型
List<T>では、さまざまな型を扱えます。
C#List<int> numbers = new List<int>();
List<double> prices = new List<double>();
List<string> names = new List<string>();
List<bool> flags = new List<bool>();
独自に作成したクラスも扱えます。
C#class User
{
public string Name { get; set; }
public int Age { get; set; }
}
List<User> users = new List<User>();
実務では、List<string>やList<int>だけでなく、List<User>、List<Product>、List<Order>のように、クラスの一覧として使うことが多いです。
2-4. varを使ったListの宣言
C#では、varを使ってListを宣言することもできます。
C#var numbers = new List<int>();
var names = new List<string>();
varを使っても、型がなくなるわけではありません。右辺から型が推論されるだけです。
C#var numbers = new List<int>();
numbers.Add(100);
この場合、numbersはList<int>として扱われます。
コードが短くなるため便利ですが、初心者のうちは型を意識するために、まずはList<int>やList<string>のように明示的に書くのもおすすめです。
3. C# Listの初期化方法
3-1. 空のListを作成する方法
空のListを作成する基本形は次のとおりです。
C#List<int> numbers = new List<int>();
文字列のListなら次のように書きます。
C#List<string> names = new List<string>();
作成直後のListには要素が入っていません。
C#Console.WriteLine(numbers.Count); // 0
Countを使うと、Listに入っている要素数を取得できます。
3-2. 初期値を指定してListを作成する方法
Listは、作成時に初期値を指定できます。
C#List<int> numbers = new List<int> { 10, 20, 30 };
文字列の場合は次のように書きます。
C#List<string> fruits = new List<string> { "Apple", "Banana", "Orange" };
この書き方は、あらかじめ入れるデータが決まっている場合に便利です。
C#foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
3-3. 配列からListを作成する方法
配列からListを作成することもできます。
C#string[] array = { "Tokyo", "Osaka", "Nagoya" };
List<string> cities = new List<string>(array);
配列で持っているデータを、あとから追加・削除しやすい形に変えたい場合に便利です。
また、LINQのToListを使う方法もあります。
C#using System.Linq;
string[] array = { "Tokyo", "Osaka", "Nagoya" };
List<string> cities = array.ToList();
ToListを使うには、通常System.Linqが必要です。
3-4. オブジェクトのListを初期化する方法
独自クラスのListも初期化できます。
C#class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
C#List<Product> products = new List<Product>
{
new Product { Name = "Pen", Price = 100 },
new Product { Name = "Notebook", Price = 300 },
new Product { Name = "Bag", Price = 2500 }
};
オブジェクトのListを使うと、複数のプロパティを持つデータをまとめて管理できます。
C#foreach (Product product in products)
{
Console.WriteLine($"{product.Name}: {product.Price}円");
}
4. C# Listに要素を追加する方法
4-1. Addで要素を1つ追加する
Listに要素を1つ追加するには、Addメソッドを使います。
C#List<string> names = new List<string>();
names.Add("田中");
names.Add("佐藤");
names.Add("鈴木");
追加した要素は、Listの末尾に入ります。
C#Console.WriteLine(names[0]); // 田中
Console.WriteLine(names[1]); // 佐藤
Console.WriteLine(names[2]); // 鈴木
AddはC# Listで最もよく使うメソッドのひとつです。
4-2. AddRangeで複数の要素を追加する
複数の要素をまとめて追加する場合は、AddRangeを使います。
C#List<int> numbers = new List<int> { 1, 2, 3 };
numbers.AddRange(new int[] { 4, 5, 6 });
結果は次のようになります。
C#// 1, 2, 3, 4, 5, 6
別のListを追加することもできます。
C#List<int> list1 = new List<int> { 1, 2 };
List<int> list2 = new List<int> { 3, 4 };
list1.AddRange(list2);
AddRangeは、配列やListなど、複数の値を一括で追加したいときに便利です。
4-3. Insertで指定位置に要素を追加する
指定した位置に要素を追加したい場合は、Insertを使います。
C#List<string> fruits = new List<string> { "Apple", "Orange" };
fruits.Insert(1, "Banana");
この場合、インデックス1の位置に"Banana"が追加されます。
C#// Apple, Banana, Orange
Insertを使うと、既存の要素は後ろにずれます。
ただし、存在しない範囲のインデックスを指定するとエラーになるため注意が必要です。
4-4. InsertRangeで複数要素を指定位置に追加する
複数の要素を指定位置に追加する場合は、InsertRangeを使います。
C#List<int> numbers = new List<int> { 1, 5 };
numbers.InsertRange(1, new int[] { 2, 3, 4 });
結果は次のようになります。
C#// 1, 2, 3, 4, 5
InsertRangeは、Listの途中に複数のデータを差し込みたい場合に便利です。
5. C# Listの要素を取得・参照する方法
5-1. インデックスを指定して要素を取得する
Listの要素は、配列と同じようにインデックスで取得できます。
C#List<string> fruits = new List<string> { "Apple", "Banana", "Orange" };
Console.WriteLine(fruits[0]); // Apple
Console.WriteLine(fruits[1]); // Banana
Console.WriteLine(fruits[2]); // Orange
C#のインデックスは0から始まります。最初の要素は[0]、2番目の要素は[1]です。
存在しないインデックスにアクセスするとエラーになります。
C#// Console.WriteLine(fruits[3]); // エラー
5-2. Countで要素数を取得する
Listの要素数を取得するには、Countプロパティを使います。
C#List<int> numbers = new List<int> { 10, 20, 30 };
Console.WriteLine(numbers.Count); // 3
最後の要素を取得したい場合は、Count - 1を使います。
C#Console.WriteLine(numbers[numbers.Count - 1]); // 30
ただし、Listが空の場合はnumbers.Count - 1が-1になってしまうため、事前に要素数を確認しましょう。
C#if (numbers.Count > 0)
{
Console.WriteLine(numbers[numbers.Count - 1]);
}
5-3. foreachでListの要素を順番に処理する
Listの要素を順番に処理するには、foreachが便利です。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
foreach (string name in names)
{
Console.WriteLine(name);
}
foreachを使うと、インデックスを意識せずに全要素を処理できます。
読み取り中心の処理では、foreachがわかりやすくおすすめです。
5-4. for文でインデックスを使って処理する
インデックス番号も使いたい場合は、for文を使います。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
for (int i = 0; i < names.Count; i++)
{
Console.WriteLine($"{i}: {names[i]}");
}
出力例は次のようになります。
C#// 0: 田中
// 1: 佐藤
// 2: 鈴木
要素の位置を使って処理したい場合や、特定のインデックスだけ処理したい場合はfor文が向いています。
6. C# Listの要素を変更する方法
6-1. インデックスを指定して値を更新する
Listの要素は、インデックスを指定して変更できます。
C#List<string> fruits = new List<string> { "Apple", "Banana", "Orange" };
fruits[1] = "Grape";
結果は次のようになります。
C#// Apple, Grape, Orange
インデックスを指定して更新する場合も、範囲外アクセスには注意が必要です。
C#if (fruits.Count > 1)
{
fruits[1] = "Grape";
}
6-2. 条件に一致する要素を変更する
条件に一致する要素を変更したい場合は、FindIndexなどを使うと便利です。
C#List<string> names = new List<string> { "Tanaka", "Sato", "Suzuki" };
int index = names.FindIndex(name => name == "Sato");
if (index >= 0)
{
names[index] = "Yamada";
}
FindIndexは、条件に一致する最初の要素のインデックスを返します。見つからない場合は-1を返します。
複数の要素を変更したい場合は、for文を使う方法もあります。
C#List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
for (int i = 0; i < numbers.Count; i++)
{
if (numbers[i] % 2 == 0)
{
numbers[i] = numbers[i] * 10;
}
}
この例では、偶数だけを10倍にしています。
6-3. オブジェクトListのプロパティを変更する
クラスのListでは、条件に一致するオブジェクトを取得して、プロパティを変更できます。
C#class User
{
public string Name { get; set; }
public int Age { get; set; }
}
C#List<User> users = new List<User>
{
new User { Name = "田中", Age = 20 },
new User { Name = "佐藤", Age = 25 }
};
User user = users.Find(u => u.Name == "佐藤");
if (user != null)
{
user.Age = 26;
}
List<User>の中にあるUserオブジェクトは参照型なので、取得した変数のプロパティを変更すると、List内のオブジェクトにも反映されます。
6-4. 値型と参照型で変更時に注意するポイント
intやdoubleなどは値型です。値型のListでは、要素を取り出して変数に代入し、その変数を変更してもListの中身は変わりません。
C#List<int> numbers = new List<int> { 10, 20, 30 };
int value = numbers[1];
value = 999;
Console.WriteLine(numbers[1]); // 20
Listの中身を変えたい場合は、インデックスを指定して更新する必要があります。
C#numbers[1] = 999;
一方、クラスは参照型です。
C#User user = users[0];
user.Age = 30;
この場合、List内のオブジェクトのプロパティも変更されます。
値型と参照型の違いは、C# Listを使ううえで重要なポイントです。
7. C# Listから要素を削除する方法
7-1. Removeで指定した要素を削除する
指定した要素を削除するには、Removeを使います。
C#List<string> fruits = new List<string> { "Apple", "Banana", "Orange" };
fruits.Remove("Banana");
結果は次のようになります。
C#// Apple, Orange
Removeは、指定した値と一致する最初の要素を削除します。同じ値が複数ある場合、最初に見つかった要素だけが削除されます。
C#List<int> numbers = new List<int> { 1, 2, 2, 3 };
numbers.Remove(2);
// 1, 2, 3
7-2. RemoveAtで指定位置の要素を削除する
インデックスを指定して削除する場合は、RemoveAtを使います。
C#List<string> fruits = new List<string> { "Apple", "Banana", "Orange" };
fruits.RemoveAt(1);
結果は次のようになります。
C#// Apple, Orange
RemoveAtは、指定した位置の要素を削除します。インデックスが範囲外の場合はエラーになるため、事前に確認すると安全です。
C#if (fruits.Count > 1)
{
fruits.RemoveAt(1);
}
7-3. RemoveRangeで範囲指定して削除する
複数の要素を範囲指定して削除する場合は、RemoveRangeを使います。
C#List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
numbers.RemoveRange(1, 3);
この例では、インデックス1から3個の要素を削除します。
C#// 1, 5
RemoveRange(開始インデックス, 削除する個数)という形で指定します。
7-4. RemoveAllで条件に一致する要素を削除する
条件に一致する要素をすべて削除したい場合は、RemoveAllを使います。
C#List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
numbers.RemoveAll(n => n % 2 == 0);
この例では、偶数をすべて削除しています。
C#// 1, 3, 5
文字列のListでも使えます。
C#List<string> names = new List<string> { "Tanaka", "Sato", "Suzuki" };
names.RemoveAll(name => name.StartsWith("S"));
条件に合うデータをまとめて削除したいときに便利です。
7-5. Clearですべての要素を削除する
Listの要素をすべて削除するには、Clearを使います。
C#List<int> numbers = new List<int> { 1, 2, 3 };
numbers.Clear();
Console.WriteLine(numbers.Count); // 0
Clearを使うと、List自体は残したまま、中身だけを空にできます。
8. C# Listで要素を検索する方法
8-1. Containsで要素が存在するか確認する
Listに特定の要素が含まれているか確認するには、Containsを使います。
C#List<string> fruits = new List<string> { "Apple", "Banana", "Orange" };
bool exists = fruits.Contains("Banana");
Console.WriteLine(exists); // True
Containsは、存在すればtrue、存在しなければfalseを返します。
単純に「その値があるかどうか」を調べたい場合に便利です。
8-2. IndexOfで要素の位置を取得する
要素の位置を取得したい場合は、IndexOfを使います。
C#List<string> fruits = new List<string> { "Apple", "Banana", "Orange" };
int index = fruits.IndexOf("Banana");
Console.WriteLine(index); // 1
見つからない場合は-1が返ります。
C#int index = fruits.IndexOf("Grape");
Console.WriteLine(index); // -1
検索結果をもとに要素を更新したい場合などに使えます。
8-3. Findで条件に一致する最初の要素を取得する
条件に一致する最初の要素を取得するには、Findを使います。
C#List<int> numbers = new List<int> { 5, 12, 18, 3 };
int result = numbers.Find(n => n > 10);
Console.WriteLine(result); // 12
この例では、10より大きい最初の値である12が取得されます。
オブジェクトのListでもよく使います。
C#User user = users.Find(u => u.Name == "田中");
条件に一致するデータを1件だけ取得したい場合に便利です。
8-4. FindAllで条件に一致する複数要素を取得する
条件に一致するすべての要素を取得したい場合は、FindAllを使います。
C#List<int> numbers = new List<int> { 5, 12, 18, 3, 20 };
List<int> results = numbers.FindAll(n => n > 10);
結果は次のようになります。
C#// 12, 18, 20
FindAllは、条件に一致した要素を新しいListとして返します。
8-5. LINQのWhere・FirstOrDefaultとの違い
C#では、Listの検索にLINQを使うことも多いです。
C#using System.Linq;
Whereは、条件に一致する複数の要素を取得します。
C#var results = numbers.Where(n => n > 10);
FirstOrDefaultは、条件に一致する最初の要素を取得します。
C#int result = numbers.FirstOrDefault(n => n > 10);
FindやFindAllはList<T>のメソッドです。一方、WhereやFirstOrDefaultはLINQのメソッドで、List<T>以外のコレクションにも使いやすいのが特徴です。
簡単に使い分けるなら、次のように考えるとよいでしょう。
| 目的 | 使うメソッド |
|---|---|
| 値が含まれているか確認 | Contains |
| 位置を取得 | IndexOf |
| 条件に合う最初の要素を取得 | Find / FirstOrDefault |
| 条件に合う複数要素を取得 | FindAll / Where |
9. C# Listをソートする方法
9-1. Sortで昇順に並び替える
Listを昇順に並び替えるには、Sortを使います。
C#List<int> numbers = new List<int> { 30, 10, 20 };
numbers.Sort();
結果は次のようになります。
C#// 10, 20, 30
Sortは、元のListそのものを並び替えます。
C#foreach (int number in numbers)
{
Console.WriteLine(number);
}
数値のListであれば、小さい順に並びます。
9-2. Reverseで逆順に並び替える
Listの順番を逆にするには、Reverseを使います。
C#List<int> numbers = new List<int> { 10, 20, 30 };
numbers.Reverse();
結果は次のようになります。
C#// 30, 20, 10
降順に並び替えたい場合は、SortしてからReverseする方法があります。
C#numbers.Sort();
numbers.Reverse();
ただし、LINQのOrderByDescendingを使う方法もよく使われます。
9-3. 文字列Listをソートする
文字列のListもSortで並び替えできます。
C#List<string> names = new List<string> { "Suzuki", "Tanaka", "Sato" };
names.Sort();
結果はアルファベット順に並びます。
C#// Sato, Suzuki, Tanaka
日本語文字列の場合も並び替えはできますが、期待する五十音順と完全に一致しない場合があります。日本語の並び順を厳密に扱いたい場合は、カルチャや比較方法を意識する必要があります。
9-4. オブジェクトListを特定プロパティでソートする
オブジェクトのListを特定のプロパティで並び替えるには、Sortに比較処理を指定します。
C#class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
C#List<Product> products = new List<Product>
{
new Product { Name = "Pen", Price = 100 },
new Product { Name = "Bag", Price = 2500 },
new Product { Name = "Notebook", Price = 300 }
};
products.Sort((a, b) => a.Price.CompareTo(b.Price));
この例では、Priceが安い順に並び替えています。
C#foreach (Product product in products)
{
Console.WriteLine($"{product.Name}: {product.Price}円");
}
降順にしたい場合は、比較の順番を逆にします。
C#products.Sort((a, b) => b.Price.CompareTo(a.Price));
9-5. LINQのOrderBy・OrderByDescendingを使う方法
LINQを使うと、より読みやすくソートできます。
C#using System.Linq;
昇順に並び替える場合はOrderByを使います。
C#var sortedProducts = products.OrderBy(p => p.Price).ToList();
降順に並び替える場合はOrderByDescendingを使います。
C#var sortedProducts = products.OrderByDescending(p => p.Price).ToList();
Sortは元のListを変更しますが、OrderByは並び替えた結果を返します。元のListを変更したくない場合は、LINQのOrderByが便利です。
10. C# Listでよく使う便利なメソッド
10-1. Existsで条件に一致する要素があるか確認する
条件に一致する要素が存在するか確認するには、Existsを使います。
C#List<int> numbers = new List<int> { 5, 12, 18 };
bool exists = numbers.Exists(n => n > 10);
Console.WriteLine(exists); // True
Existsは、条件に一致する要素が1つでもあればtrueを返します。
10-2. Anyで条件判定する
LINQのAnyでも、条件に一致する要素があるか確認できます。
C#using System.Linq;
List<int> numbers = new List<int> { 5, 12, 18 };
bool exists = numbers.Any(n => n > 10);
Anyは、Listが空かどうかを判定するときにも使えます。
C#if (numbers.Any())
{
Console.WriteLine("要素があります");
}
Count > 0でも判定できます。
C#if (numbers.Count > 0)
{
Console.WriteLine("要素があります");
}
10-3. Selectで要素を変換する
Listの各要素を別の形に変換したい場合は、LINQのSelectを使います。
C#List<int> numbers = new List<int> { 1, 2, 3 };
List<int> doubled = numbers.Select(n => n * 2).ToList();
結果は次のようになります。
C#// 2, 4, 6
オブジェクトのListから特定のプロパティだけを取り出すこともできます。
C#List<string> productNames = products.Select(p => p.Name).ToList();
Selectは、データ変換で非常によく使われます。
10-4. ToArrayでListを配列に変換する
Listを配列に変換するには、ToArrayを使います。
C#List<string> names = new List<string> { "田中", "佐藤", "鈴木" };
string[] array = names.ToArray();
配列を必要とするメソッドに渡したい場合などに便利です。
10-5. ToListでIEnumerableをListに変換する
LINQの結果などをListに変換するには、ToListを使います。
C#using System.Linq;
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
List<int> evenNumbers = numbers.Where(n => n % 2 == 0).ToList();
Whereの結果はそのままだとIEnumerable<int>です。Listとして扱いたい場合はToListで変換します。
C#Console.WriteLine(evenNumbers.Count); // 2
11. C# Listを使うときの注意点
11-1. インデックス範囲外エラーに注意する
Listでよくあるエラーが、存在しないインデックスにアクセスすることです。
C#List<int> numbers = new List<int> { 10, 20, 30 };
// Console.WriteLine(numbers[3]); // エラー
要素数が3の場合、使えるインデックスは0、1、2です。
安全にアクセスするには、Countを確認しましょう。
C#int index = 2;
if (index >= 0 && index < numbers.Count)
{
Console.WriteLine(numbers[index]);
}
11-2. nullの扱いに注意する
Listの変数自体がnullの場合、メソッドを呼び出すとエラーになります。
C#List<string> names = null;
// names.Add("田中"); // エラー
Listを使う前に初期化しておきましょう。
C#List<string> names = new List<string>();
names.Add("田中");
また、List<string>にはnull要素を入れることもできます。
C#List<string> names = new List<string> { "田中", null, "佐藤" };
この場合、文字列メソッドを呼び出す前にnullチェックが必要です。
C#foreach (string name in names)
{
if (name != null)
{
Console.WriteLine(name.Length);
}
}
11-3. foreach中にListを変更するときの注意点
foreachでListを回している最中に、要素を追加・削除するとエラーになることがあります。
C#List<int> numbers = new List<int> { 1, 2, 3, 4 };
foreach (int number in numbers)
{
if (number % 2 == 0)
{
// numbers.Remove(number); // エラーの原因
}
}
条件に一致する要素を削除したい場合は、RemoveAllを使うと安全です。
C#numbers.RemoveAll(n => n % 2 == 0);
または、後ろからfor文で削除する方法もあります。
C#for (int i = numbers.Count - 1; i >= 0; i--)
{
if (numbers[i] % 2 == 0)
{
numbers.RemoveAt(i);
}
}
Listをループ中に変更する場合は、処理方法に注意しましょう。
11-4. Listの容量とパフォーマンスの基本
List<T>は内部的に配列を使ってデータを管理しています。要素が増えて容量が足りなくなると、内部配列を拡張します。
通常はあまり意識しなくても問題ありませんが、大量の要素を追加する場合は、あらかじめ容量を指定できます。
C#List<int> numbers = new List<int>(1000);
このように書くと、最初からある程度の容量を確保できます。
容量はCapacityで確認できます。
C#Console.WriteLine(numbers.Capacity);
要素数はCount、内部的な確保容量はCapacityです。この2つは意味が違います。
11-5. 大量データを扱う場合の考え方
大量データを扱う場合、Listが常に最適とは限りません。
たとえば、特定のキーで高速に検索したい場合は、Dictionary<TKey, TValue>のほうが向いています。
C#Dictionary<int, string> users = new Dictionary<int, string>();
users.Add(1, "田中");
users.Add(2, "佐藤");
重複を避けたい場合は、HashSet<T>が向いていることもあります。
C#HashSet<string> tags = new HashSet<string>();
tags.Add("C#");
tags.Add("List");
tags.Add("C#");
順番にデータを管理したい場合はList<T>、キーで管理したい場合はDictionary、重複を避けたい場合はHashSetというように使い分けるとよいでしょう。
12. C# Listの実践サンプルコード
12-1. 数値Listを使った基本サンプル
数値のListを作成し、追加、合計、平均を求めるサンプルです。
C#using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<int> scores = new List<int>();
scores.Add(80);
scores.Add(90);
scores.Add(70);
int total = scores.Sum();
double average = scores.Average();
Console.WriteLine($"合計: {total}");
Console.WriteLine($"平均: {average}");
}
}
SumやAverageを使うには、System.Linqを追加します。
12-2. 文字列Listを使った追加・検索サンプル
文字列のListで、要素の追加と検索を行うサンプルです。
C#using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> fruits = new List<string>
{
"Apple",
"Banana",
"Orange"
};
fruits.Add("Grape");
if (fruits.Contains("Banana"))
{
Console.WriteLine("Bananaがあります");
}
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
}
}
Containsを使うと、指定した文字列がListに含まれているか簡単に確認できます。
12-3. クラスのListを使った管理サンプル
クラスのListを使って商品情報を管理するサンプルです。
C#using System;
using System.Collections.Generic;
class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
class Program
{
static void Main()
{
List<Product> products = new List<Product>
{
new Product { Name = "Pen", Price = 100 },
new Product { Name = "Notebook", Price = 300 },
new Product { Name = "Bag", Price = 2500 }
};
Product product = products.Find(p => p.Name == "Notebook");
if (product != null)
{
Console.WriteLine($"{product.Name}は{product.Price}円です");
}
}
}
実務では、このように独自クラスのListを使う場面が多くあります。
12-4. ListとLINQを組み合わせた実践例
ListとLINQを組み合わせると、条件抽出や並び替えを簡潔に書けます。
C#using System;
using System.Collections.Generic;
using System.Linq;
class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
class Program
{
static void Main()
{
List<Product> products = new List<Product>
{
new Product { Name = "Pen", Price = 100 },
new Product { Name = "Notebook", Price = 300 },
new Product { Name = "Bag", Price = 2500 },
new Product { Name = "Eraser", Price = 80 }
};
List<Product> result = products
.Where(p => p.Price >= 100)
.OrderBy(p => p.Price)
.ToList();
foreach (Product product in result)
{
Console.WriteLine($"{product.Name}: {product.Price}円");
}
}
}
この例では、価格が100円以上の商品を抽出し、価格の安い順に並び替えています。
LINQを使うことで、C# Listの操作を読みやすく書けます。
13. C# Listに関するよくある質問
13-1. ListとArrayListの違いは?
List<T>はジェネリックコレクションで、扱う型を指定できます。
C#List<int> numbers = new List<int>();
一方、ArrayListは古いコレクションで、さまざまな型を混在させることができます。
C#ArrayList list = new ArrayList();
list.Add(10);
list.Add("abc");
ArrayListは型安全ではないため、現在のC#では基本的にList<T>を使うのがおすすめです。
13-2. ListとDictionaryはどう使い分ける?
List<T>は、データを順番に並べて管理したい場合に向いています。
C#List<string> names = new List<string>
{
"田中",
"佐藤",
"鈴木"
};
Dictionary<TKey, TValue>は、キーを使って値を管理したい場合に向いています。
C#Dictionary<int, string> users = new Dictionary<int, string>
{
{ 1, "田中" },
{ 2, "佐藤" }
};
順番に処理したいならList、IDやキーで素早く検索したいならDictionaryを使うとよいでしょう。
13-3. Listの要素数を取得するには?
Listの要素数はCountで取得します。
C#List<int> numbers = new List<int> { 10, 20, 30 };
Console.WriteLine(numbers.Count); // 3
配列ではLengthを使いますが、ListではCountを使う点に注意しましょう。
C#int[] array = { 10, 20, 30 };
Console.WriteLine(array.Length); // 配列
Console.WriteLine(numbers.Count); // List
13-4. Listが空かどうか判定するには?
Listが空かどうかは、Countで判定できます。
C#if (numbers.Count == 0)
{
Console.WriteLine("Listは空です");
}
LINQのAnyを使う方法もあります。
C#if (!numbers.Any())
{
Console.WriteLine("Listは空です");
}
ただし、Anyを使う場合はSystem.Linqが必要です。
13-5. Listの重複を削除するには?
Listの重複を削除するには、LINQのDistinctを使います。
C#using System.Linq;
List<int> numbers = new List<int> { 1, 2, 2, 3, 3, 4 };
List<int> uniqueNumbers = numbers.Distinct().ToList();
結果は次のようになります。
C#// 1, 2, 3, 4
文字列のListでも同じように使えます。
C#List<string> names = new List<string>
{
"田中",
"佐藤",
"田中"
};
List<string> uniqueNames = names.Distinct().ToList();
重複を最初から許可したくない場合は、HashSet<T>を使う方法もあります。
まとめ
C#のList<T>は、複数のデータを扱ううえで非常に重要なコレクションです。配列と違って要素をあとから追加・削除できるため、実務でも幅広く使われます。
基本的な使い方としては、まずusing System.Collections.Generic;を追加し、List<int>やList<string>のように型を指定して宣言します。
要素の追加にはAddやAddRange、削除にはRemove、RemoveAt、RemoveAll、検索にはContains、Find、FindAllなどを使います。並び替えにはSortやReverse、LINQのOrderByが便利です。
また、C# ListはLINQと組み合わせることで、条件抽出、変換、集計、ソートなどを簡潔に書けます。
初心者のうちは、次の操作を重点的に覚えるとよいでしょう。
Addで追加するRemoveやRemoveAtで削除するCountで要素数を取得するforeachで順番に処理するFindやWhereで検索するSortやOrderByで並び替える
C# Listの基本を理解すれば、配列より柔軟にデータを扱えるようになります。まずは小さなサンプルコードを書きながら、追加、削除、検索、ソートの流れを実際に試してみましょう。

