C# Listの使い方を基礎から解説|初期化・追加・削除・検索・ソートまでわかる入門ガイド

はじめに

C#で複数のデータを扱うときによく使われるのがList<T>です。List<T>は、要素数をあとから増やしたり減らしたりできるコレクションで、実務のC#開発でも非常に頻繁に登場します。

たとえば、ユーザー名の一覧、商品データの一覧、検索結果、スコアの集合など、同じ種類のデータをまとめて管理したい場面でListは便利です。

この記事では、C# Listの基本から、初期化、追加、削除、検索、ソート、LINQとの組み合わせ、注意点、実践サンプルまでを入門者向けに解説します。

1. C#のListとは?配列との違いと使う場面

1-1. List<T>の基本概要

C#のList<T>は、同じ型のデータを順番に格納できるコレクションです。

Tには、intstringdouble、独自クラスなど、扱いたいデータ型を指定します。

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);

この場合、numbersList<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. 値型と参照型で変更時に注意するポイント

intdoubleなどは値型です。値型の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);

FindFindAllList<T>のメソッドです。一方、WhereFirstOrDefaultは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の場合、使えるインデックスは012です。

安全にアクセスするには、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}");
}
}

SumAverageを使うには、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>のように型を指定して宣言します。

要素の追加にはAddAddRange、削除にはRemoveRemoveAtRemoveAll、検索にはContainsFindFindAllなどを使います。並び替えにはSortReverse、LINQのOrderByが便利です。

また、C# ListはLINQと組み合わせることで、条件抽出、変換、集計、ソートなどを簡潔に書けます。

初心者のうちは、次の操作を重点的に覚えるとよいでしょう。

  • Addで追加する

  • RemoveRemoveAtで削除する

  • Countで要素数を取得する

  • foreachで順番に処理する

  • FindWhereで検索する

  • SortOrderByで並び替える

C# Listの基本を理解すれば、配列より柔軟にデータを扱えるようになります。まずは小さなサンプルコードを書きながら、追加、削除、検索、ソートの流れを実際に試してみましょう。