同じ型の値をまとめて管理する場合、C#では List<T> を使います。
この List(リスト)は、配列とは違って要素を追加・削除・検索できるメソッドが扱えるので、プログラム開発ではよく使用するクラスです。
今回は、List の基本的な使い方をまとめて紹介したいと思います。この記事を参考にして、Listの使い方をマスターしましょう。
オススメの参考書
C#の使い方が丁寧に解説しており、「基礎からしっかりと学びたい」という初心者の方にオススメの一冊です。サンプルコードも記載してあり、各章の最後に復習問題があるので理解度を確認しながら読み進めることができます。新しい C# のバージョンにも対応している書籍です。
List(リスト)て何?
List(リスト)は指定した型やオブジェクトをまとめて管理する事ができるコレクションです。
List<T> クラス T:リスト内のデータの型
List を管理するための様々なメソッドが用意されており、要素の追加や削除、検索、並び替えなどを行う事ができます。リストの中の1つ1つのデータを「要素」と言います。
似たような役割を持つものとして「配列」があります。どちらも要素の集合体ではありますが、List の場合は動的に要素の追加・削除・挿入・変更という操作ができるという違いがあります。
配列と List の違い
- 配列は宣言時に指定した要素数を上回る要素の追加はできない。
- List は要素を管理する仕組み(追加・削除・挿入・変更)がある。
また、List から配列へ変換することができます。反対に配列から List へ変換もできます。これらの変換を行うには、Linq の ToArray() もしくは ToList() を使うだけなので簡単に変換が可能です。
Listの使い方
それでは List の使い方を紹介していきます。
名前空間の宣言
List クラスは System.Collections.Generic という名前空間に定義されています。
使用する際はファイルのヘッダーに次のように名前空間を宣言します。
// 名前空間の宣言(必須)
using System.Collections.Generic;
これがないと List が使えないので注意しましょう。
初期化
List はクラスなので、new 演算子でインスタンスを生成して使います。
- List<データの型> 変数名 = new List<データの型>();
- List<データの型> 変数名 = new List<データの型>() { 初期化子 };
- List<データの型> 変数名 = new List<データの型> { 初期化子 };
このクラスはある特定の型の入れ物として機能を持つジェネリッククラスなので、データの型を指定する必要があります。データの型としては、int や string、double、datetime、複合型などがあります。
また、インスタンスを生成すると同時に初期値も設定する事ができます。初期値は必要に応じて設定するようにしましょう。
// int型のリストを生成する場合
var intList = new List<int>();
// string型のリストを生成する場合
var stringList = new List<string>();
// 複合型(Personクラスは下記に記載)のリストを生成する場合
var personList = new List<Person>();
// インスタンスの生成と同時に初期値を設定する場合
var intList = new List<int>()
{
1, 2, 3, 4 // これらの値が初期値になる
};
var stringList = new List<string>()
{
"taro", "kazuma", "yuki", "shohei"
};
var personList = new List<Person>()
{
new Person(){ Name = "taro", Age = 19 }, // Personクラスも初期化する
new Person(){ Name = "kazuma", Age = 17 },
new Person(){ Name = "yuki", Age = 21 },
new Person(){ Name = "shohei", Age = 25 },
};
// Personクラス
class Person
{
public string Name; // 名前
public int Age; // 年齢
}
ちなみに、配列をコンストラクタの引数に渡すことでリストの初期値として設定する事ができます。
// 配列をコンストラクタの引数に渡す場合
var array = new int[]{ 1, 2, 3, 4 };
var list = new List<int>(array);
// 省略して書く事もできる
var list = new List<int>(new []{ 1, 2, 3, 4 });
要素を取得する
List の要素を取得する方法はいくつかあります。要素を1つだけ取得するなら、インデックスを指定すれば取得ができます。
// リストの宣言
var intList = new List<int>()
{
1, 2, 3, 4
};
var item = intList[1];
Debug.WriteLine(item);
// 出力結果
// 2
要素をすべて取得したい場合は、for 文や foreach、Linq を使います。
// リストの宣言
var intList = new List<int>()
{
1, 2, 3, 4
};
// for文を使う
for (int i = 0; i < intList.Count; i++)
{
Debug.WriteLine(intList[i]); // 1 2 3 4が出力される
}
// foreach文を使う
foreach(var item in intList)
{
Debug.WriteLine(item); // 1 2 3 4が出力される
}
// LINQを使う
intList.ForEach(x => Debug.WriteLine(x));
要素を更新する
List の要素を更新するには、要素のインデックスを指定して要素の書き換えをします。
// リストの宣言
var intList = new List<int>()
{
1, 2, 3, 4
};
// 要素を更新する
intList[0] = 5;
intList.ForEach(x => Debug.WriteLine(x));
// 出力結果
// 5
// 2
// 3
// 4
要素を追加する(Add,AddRange)
List の末尾に要素を追加するメソッドは次の通り2つあります。
- Add(T) : 要素をリストの末尾に追加
- AddRange(IEnumerable<T>) : 複数の要素をまとめてリストに追加
要素を1つ追加するには「Add」を使います。追加された要素は List の末尾に配置されます。
// リストの宣言
var intList = new List<int>();
// 要素の追加
intList.Add(3);
intList.Add(7);
intList.Add(9);
values.ForEach(x => Debug.WriteLine(x));
// 出力結果
// 3
// 7
// 9
要素をまとめて追加するには「AddRange」を使います。追加された要素は List の末尾に配置されます。
// リストの宣言
var intList1 = new List<int>() { 1, 2, 3 };
var intList2 = new List<int>() { 4, 5, 6 };
// 要素の追加
intList1.AddRange(intList2);
intList1.ForEach(x => Debug.WriteLine(x));
// 出力結果
// 1
// 2
// 3
// 4
// 5
// 6
要素を挿入する(Insert)
List の指定したインデックスの位置に要素を挿入するメソッドがあります。
Insert(Int32, T) : 指定した位置に要素を挿入
第1引数に0から始まる要素のインデックス、第2引数には追加する要素を指定します。List の末尾以外に要素を追加したい場合に Insert を使います。
// リストの宣言
var intList = new List<int>() { 1, 2, 3 };
// 要素の挿入
intList.Insert(0, 4);
intList.Insert(2, 5);
intList.ForEach(x => Debug.WriteLine(x));
// 出力結果
// 4
// 1
// 5
// 2
// 3
要素を削除する(Remove,RemoveAt,Clear)
List の要素を削除するメソッドは次の通り3つあります。
- Remove(T) : 最初に一致した要素を削除
- RemoveAt(Int32) : 指定したインデックスにある要素を削除
- Clear() : 要素をすべて削除
要素を1つだけ削除するには「Remove」を使います。このメソッドは最初に一致した要素を List から削除します。
// リストの宣言
var intList = new List<int>() { 1, 2, 1, 2 };
// 要素の削除
intList.Remove(2);
intList.ForEach(x => Debug.WriteLine(x));
// 出力結果
// 1
// 1
// 2
指定したインデックスの要素を削除するには「RemoveAt」を使います。
// リストの宣言
var intList = new List<int>() { 1, 2, 1, 2 };
// 要素の削除
intList.RemoveAt(3);
intList.ForEach(x => Debug.WriteLine(x));
// 出力結果
// 1
// 2
// 1
List の要素をすべて削除するには「Clear」を使います。
Clear メソッドは List の要素をすべて削除しますが、List の容量(Capacity)は削除する前と変わりません。例えば、リストから100個の要素を全部削除しても100個分の容量を入れられる空のリストになっています。
そこで容量を最適化するには TrimExcess メソッドを使います。
// リストの宣言
var intList = new List<int>();
Debug.WriteLine($"Capacity: {intList.Capacity}");
// 要素の追加
intList.AddRange(new int[] { 1, 2, 1, 2 });
Debug.WriteLine("->要素追加");
Debug.WriteLine($"Count: {intList.Count}");
Debug.WriteLine($"Capacity: {intList.Capacity}");
// 要素の削除
intList.Clear();
Debug.WriteLine("->要素全削除");
Debug.WriteLine($"Count: {intList.Count}");
Debug.WriteLine($"Capacity: {intList.Capacity}");
// リスト最適化
intList.TrimExcess();
Debug.WriteLine("->リスト最適化");
Debug.WriteLine($"Count: {intList.Count}");
Debug.WriteLine($"Capacity: {intList.Capacity}");
// 出力結果
// Capacity: 0
// ->要素追加
// Count: 4
// Capacity: 4
// ->要素全削除
// Count: 0
// Capacity: 4
// ->リスト最適化
// Count: 0
// Capacity: 0
要素をソートする(Sort)
List の要素をソート(並び替え)するには、Sort メソッドを使います。
Sort(T) : 要素全体を並び替び
ソートはデフォルトでは大文字小文字を区別する方法で大小が比較されて並び替えが行われます。
// リストの宣言
var stringList = new List<string>() { "3", "A", "2", "a", "B", "1", "b" };
// 要素を並び替え
stringList.Sort();
stringList.ForEach(x => Debug.WriteLine(x));
// 出力結果
// 1
// 2
// 3
// a
// A
// b
// B
大文字小文字で比較しない場合は、並び替えの条件を指定する事でカスタマイズできます。また、LINQ の「OrderBy」や「OrderByDescending」メソッドを使っても並び替えができます。
// リストの宣言
var intList = new List<int>() { 6, 3, 4, 1, 5, 2 };
// 要素を並び替え(ラムダ式)
intList.Sort((x, y) => y - x);
// 要素を並び替え(LINQ)
var orderList = intList.OrderByDescending(x => x).ToList();
stringList.ForEach(x => Debug.WriteLine(x));
// 出力結果
// 6
// 5
// 4
// 3
// 2
// 1
要素を検索する(Contains,Exists,IndexOf,FindIndex)
List 内の要素を検索して条件に一致する要素を取得するためのいくつかのメソッドがあります。
- Contains(T) : 指定した要素がリスト内に含まれているどうか
- Exists(Predicate<T>) : 条件と一致する要素が含まれているかどうか
- IndexOf(T) : 指定した要素を検索し、一致した最初のインデックスを返す
- FindIndex(Predicate<T>) : 指定した条件で検索し、一致した最初のインデックスを返す
要素の検索は基本的にリストの先頭から行われます。リストの要素数が多いと、それだけ検索時間がかかっています。特に一致する要素がない場合は、末尾まで検索してから結果が返されるため、動作速度に影響を与える可能性があるので注意が必要です。
メソッドの使い方は次の通りです。
// リストの宣言
var intList = new List<int>() { 6, 3, 4, 1, 5, 2 };
// 指定した値が含まれているかどうか確認
if (intList.Contains(1))
{
Debug.WriteLine("1は含まれています");
}
// ラムダ式で条件を記述し、一致する要素があるかどうか確認
if (intList.Exists(x => x % 2 == 0))
{
Debug.WriteLine("偶数は含まれています");
}
// 指定した要素を検索し、一致した最初のインデックスを返す
int index = intList.IndexOf(2);
if (index != -1) // 戻り値のIndexが-1だと存在しない
{
Debug.WriteLine($"検索結果:{intList[index]}");
// 出力結果
// 検索結果:2
}
// 指定した条件で検索し、一致した最初のインデックスを返す
int index = intList.FindIndex(x => x % 2 == 0);
if (index != -1) // 戻り値のIndexが-1だと存在しない
{
Debug.WriteLine($"検索結果:{intList[index]}");
// 出力結果
// 検索結果:6
}
別の型へ変換する(ConvertAll)
List の要素を別の型に変換するには、ConvertAll メソッドを使います。
ConvertAll() : 要素を別の型に変換
型の変換条件についてはラムダ式で指定します。メソッドの使い方は次の通りです。
// リストの宣言
var intList = new List<int>() { 6, 3, 4, 1, 5, 2 };
// 別の型に変換する
List<string> stringList = intList.ConvertAll(x => x.ToString());
stringList.ForEach(x => Debug.WriteLine($"型:{x.GetType()} 値:{x}"));
// 出力結果
// 型:System.String 値:6
// 型:System.String 値:3
// 型:System.String 値:4
// 型:System.String 値:1
// 型:System.String 値:5
// 型:System.String 値:2
配列に変換する(ToArray)
List を配列に変換するには、ToArray メソッドを使います。配列から List に変換するには。ToList メソッドを使います。
ToArray() : Listの要素を新しい配列にコピー
メソッドの使い方は次の通りです。
// リストの宣言
var intList = new List<int>() { 6, 3, 4, 1, 5, 2 };
// 別の型に変換する
int[] intArray = intList.ToArray();
List<int> intList2 = intArray.ToList();
まとめ
この記事では、C# で使う List の基本的な使い方をまとめました。
プログラムを作成するにあたりよく使うので、使い方が分からない時はこの記事を参考にして頂ければ幸いです。
以上、最後まで読んで頂きありがとうございました。