Listクラスのメソッド

Listクラスの操作

ここではよく使われるListクラスのメソッドを紹介します。
Listクラスについての基本的な事柄はListクラスを参照してください。

配列と同じく、最初の要素番号は「0」なので注意してください。

列挙

ForEach(要素の列挙)

ForEachメソッドは、Listの全て要素に対して任意のメソッドを実行します。


static void Show(int n)
{
    Console.WriteLine(n);
}

static void Main(string[] args)
{
    List<int> lst = new List<int>() { 1, 2, 3 };
    lst.ForEach(Show);
}
1
2
3

引数は適用するメソッド名を指定します。
(関数呼び出し演算子()は記述しない)

メソッドはListの要素の型ひとつを引数に取り、void型を返すように定義します。

このメソッドでListの要素を書き換えることはできません。
要素を書き換える場合はfor文を使用してください。

メソッドには、別のメソッドを引数に指定するものがあります。
ここにはメソッド名を指定するほか、ラムダ式で記述されることが多いです。


List<int> lst = new List<int>() { 1, 2, 3 };
//引数にラムダ式を指定
lst.ForEach(n => Console.WriteLine(n));

要素の追加

Add(要素の追加)

AddメソッドはListの末尾に要素を追加します。


//空のListを作成
var lst = new List<int>();

//要素を末尾に追加
lst.Add(2);
lst.Add(3);
lst.Add(5);

foreach(var n in lst)
    Console.WriteLine(n);
2
3
5

最初に要素数ゼロのListを宣言しています。
配列の場合、要素数がゼロの配列を作ってもほとんど意味がありませんが、Listの場合は後で要素を追加できます。

Addメソッドは、常にListの末尾に新しい要素を追加します。
途中に要素を追加したい場合は次のInsertメソッドを使用します。

戻り値はありません。

Insert(要素の挿入)

Listの途中に要素を追加するにはInsertメソッドを使用します。


var lst = new List<string>() { "Apple", "Grape", "Strawberry" };

//要素を1番目に追加
lst.Insert(1, "Orange");

//要素を3番目に追加
lst.Insert(3, "Peach");

for (int i = 0; i < lst.Count; i++)
    Console.WriteLine("{0}: {1}", i, lst[i]);
0: Apple
1: Orange
2: Grape
3: Peach
4: Strawberry

第一引数に追加する要素番号、第二引数に追加したい要素を指定します。
第一引数が0未満、またはListの要素数以上の値の場合はエラー(例外)が発生します。
戻り値はありません。

要素を途中に挿入することで、以降の要素は要素番号がひとつ後ろにずらされることに注意してください。

挿入は速度がやや劣る

Listの末尾に要素を追加するAddメソッドは高速に行うことができます。
対して、途中に要素を挿入するInsertメソッドは、Addに比べると速度が劣ります。
これは「リスト」というデータ構造の特徴です。

数百件程度の追加ではほぼ差はありませんが、何万件も追加する処理では差が出てきます。
要素を大量に追加する処理を行う場合はInsertの使用は避けるか、別の手段を用いたほうがパフォーマンス的に有利な場合があります。

AddRange(Listの結合)

AddRangeメソッドは、Listの末尾に別のListを追加(結合)します。


var lst1 = new List<int>() { 1, 2, 3 };
var lst2 = new List<int>() { 4, 5, 6 };

//lst1の末尾にlst2を結合
lst1.AddRange(lst2);

foreach(var n in lst1)
    Console.WriteLine(n);
1
2
3
4
5
6

戻り値はありません。

なお、このメソッドは同じ型のListクラス以外にもIEnumerable<T>を継承するクラスであれば結合できます。
これは配列や多くのコレクションクラスが該当します。

InsertRange(Listの挿入)

Listの要素の途中に別のListを挿入するにはInsertRangeメソッドを使用します。


var lst1 = new List<string>() { "Apple", "Strawberry", "Peach" };
var lst2 = new List<string>() { "Orange", "Grape" };

//lst1の1番目の要素にlst2を追加
lst1.InsertRange(1, lst2);

foreach(var s in lst1)
    Console.WriteLine(s);
Apple
Orange
Grape
Strawberry
Peach

第一引数に追加する要素番号、第二引数に追加したいListを指定します。
第一引数が0未満、またはListの要素数以上の値の場合はエラー(例外)が発生します。
戻り値はありません。

Insertメソッドと同じく、Listを途中に挿入することによって以降の要素は要素番号が後ろにずらされます。

なお、このメソッドは同じ型のListクラス以外にもIEnumerable<T>を継承するクラスであれば結合できます。
これは配列や多くのコレクションクラスが該当します。

要素の削除

Remove(要素の削除)

Removeメソッドは指定の要素を削除します。


var lst = new List<string>()
	{ "Apple", "Strawberry", "Peach",
    "Orange", "Grape", "Strawberry" };

//要素を削除
bool bo1 = lst.Remove("Peach"); //true
bool bo2 = lst.Remove("Strawberry"); //true
bool bo3 = lst.Remove("Peach"); //false

foreach (var s in lst)
    Console.WriteLine(s);
Apple
Orange
Grape
Strawberry

Removeメソッドは要素を先頭から検索し、最初に見つかった要素を削除します。
削除に成功した場合は真を、要素が見つからなかった場合は偽を返します。

同じ値が複数存在する場合は最初に見つかった要素だけが削除されるので注意してください。

RemoveAt(要素番号を指定して削除)

RemoveAtメソッドは「値」ではなく「要素番号」を指定して要素を削除します。


var lst = new List<string>()
    { "Apple", "Grape", "Orange", "Strawberry", "Peach" };

//要素番号で削除
lst.RemoveAt(1);
lst.RemoveAt(3);

foreach (var s in lst)
    Console.WriteLine(s);
Apple
Orange
Strawberry

0未満、もしくはListの要素数以上の値を指定するとエラー(例外)になります。

最後以外の要素を削除すると、削除した後ろの要素が前に詰められます。
要素番号が変わることに注意が必要です。

Removeメソッドとは異なり、戻り値はありません。

RemoveRange(範囲を指定して削除)

要素の範囲を指定して一括削除するにはRemoveRangeメソッドを使用します。


var lst = new List<string>()
    { "Apple", "Grape", "Orange", "Strawberry", "Peach" };

//要素番号1から2つ分の要素を削除
lst.RemoveRange(1, 2);

oreach (var s in lst)
    Console.WriteLine(s);
Apple
Strawberry
Peach

RemoveRangeメソッドの第一引数には削除を開始する要素番号を指定します。
第二引数は削除する要素数を指定します。
戻り値はありません。

要素の指定が範囲外の場合はエラー(例外)が発生します。

RemoveAll(条件に一致する要素の削除)

ある条件に一致する要素をすべて削除するにはRemoveAllメソッドを使用します。


//引数が10以上なら真を返すメソッド
static bool IsGTE10(int n)
{
    return n >= 10;
}

static void Main(string[] args)
{
    var lst = new List<int>() { 8, 3, 16, 19, 2, 31 };

    //10以上の要素を全て削除
    int removed = lst.RemoveAll(IsGTE10);

    foreach (var n in lst)
        Console.WriteLine(n);

    Console.WriteLine("削除された要素数: {0}", removed);

    Console.ReadLine();
}
8
3
2
削除された要素数: 3

Removeメソッドの使用には条件判定用のメソッドが必要です。
Listクラスの要素の型をひとつ引数に取り、bool型の戻り値のメソッドを定義します。
今回は10以上の要素をすべて削除するために、引数が10以上ならば真を返すメソッドを定義しています。

このメソッドをRemoveメソッドの引数に指定することで、条件に一致する要素が取り除かれます。
このとき、メソッド名の後ろに関数呼び出し演算子()は指定しないことに注意してください。
(メソッド名のみを指定する)

戻り値は削除された要素数です。

条件判定用のメソッドは、ラムダ式を使用して記述されることが多いです。


var lst = new List<int>() { 8, 3, 16, 19, 2, 31 };

int removed = lst.RemoveAll((x) => x >= 10);

foreach (var n in lst)
    Console.WriteLine(n);

Console.WriteLine("削除された要素数: {0}", removed);
8
3
2
削除された要素数: 3

Clear(要素をすべて削除)

Clearメソッドは、Listの要素をすべて削除します。


var lst = new List<int>() { 0, 1, 2, 3, 4, 5 };

lst.Clear();

//0
Console.WriteLine(lst.Count);

これは特に説明の必要はないでしょう。
Clearメソッド実行後の要素数はゼロになります。

Listクラスの変数自体が不要になった場合は、変数にnullを代入します。


static void Func()
{
    var lst = new List<int>() { 0, 1, 2, 3, 4, 5 };

    //何か処理...

    lst.Clear();

    lst = null;
}

C#にはガベージコレクションという機能があり、不要になったデータは自動的にメモリ上から消去してくれます。
(ガベージコレクション=ゴミ拾い)
クラスの変数(インスタンス)は参照型ですから、これにnullを代入するということはメモリ上のどこも指していない状態になります。
それまでその変数保存していたデータはどこからも使用されていないことになるため、ガベージコレクションがメモリを解放してくれます。

上記のようなローカル変数は、現在のスコープ(上記の場合はFuncメソッド)を抜けた時点で寿命となるので、これも勝手にガベージコレクションがメモリ消去してくれます。
なので、上記はあまり意味のない記述ですが、メンバー変数の場合はなかなか寿命が来ないことも多く、明示的にメモリ上からデータを消去したい場合はnullを代入するのが有効な方法です。

もちろんnull代入後の変数は使用不可能となります。
ただし、再度初期化することで同じ変数を使いまわすことはできます。

なお、プログラム上のどこかで参照状態が続いている場合は「不要なデータ」ではありませんからガベージコレクションはメモリを消去してくれません。
以下のような場合はlst1が参照していた「0,1,2,3」というデータは、6行目でlst1からは参照されなくなりますが、lst2からは参照状態が続くので、メモリの消去は行われません。


static void Func()
{
    var lst1 = new List<int>() { 0, 1, 2, 3 };
    var lst2 = lst1;

    lst1 = null;
    //lst1の中身はlst2が参照しているため消えない

    //何か処理...

}//lst2の寿命によりメモリから消去

思わぬところから参照状態が続いているといつまで経ってもメモリが解放されないので注意しましょう。

コピー

GetRange(要素の部分コピー)

GetRangeメソッドは、指定の範囲の要素をコピーしたListを作成します。


var lst1 = new List<int>() { 1, 2, 3, 4, 5 };

//1番目の要素から3つ分をコピー
List<int> lst2 = lst1.GetRange(1, 3);

foreach (var n in lst2)
    Console.Write("{0} ", n);
2 3 4

第一引数はコピーを開始する要素番号、第二引数はコピーする要素数です。
戻り値は指定の範囲をコピーした新しいListクラスです。

Slice(要素の部分コピー)

.NET8以降GetRangeメソッドはSliceという名前でも使用可能です。
引数や機能は同じです。

CopyTo(配列にコピー)

CopyToメソッドは、指定の範囲の要素を別の配列にコピーします。


var lst = new List<int>() { 1, 2, 3 };
int[] arr = new int[lst.Count + 1];

lst.CopyTo(arr);

foreach (var n in arr)
    Console.Write("{0} ", n);
1 2 3 0

引数はコピー先の配列です。
先頭からコピーが開始され、コピー先配列の要素が足りない場合は実行時エラーになります。

第二引数にコピー先配列のコピー開始番号を指定することができます。
また、第一引数にListのコピー開始番号、第二引数にコピー先配列、第三引数に配列のコピー開始番号、第四引数にコピーする要素数を指定することができます。


var lst = new List<int>() { 1, 2, 3 };
int[] arr1 = new int[lst.Count + 3];
int[] arr2 = new int[lst.Count + 3];

//arr1の2番目からコピー開始
lst.CopyTo(arr1, 2);

//lstの1番目からarr2の3番目に2文字分コピー
lst.CopyTo(1, arr2, 3, 2);

foreach (var n in arr1)
    Console.Write("{0} ", n);

Console.WriteLine();
foreach (var n in arr2)
    Console.Write("{0} ", n);
0 0 1 2 3 0
0 0 0 2 3 0

変換

ToArray(Listを配列に変換)

ToArrayメソッドは、Listクラスの要素を同じ型の配列に変換します。


var lst = new List<int>() { 1, 2, 3 };

int[] arr = lst.ToArray();

foreach (var n in arr)
    Console.WriteLine(n);
1
2
3

これは要素を単純にコピーするだけ、つまりシャローコピーなのでListの要素が参照型の場合はアドレスのコピーになります。


var lst = new List<int[]>()
{
    new int[] { 1, 2 },
    new int[] { 3, 4 },
};

int[][] arr = lst.ToArray();

//変換後にコピー元の要素を書き換えると
//コピー先の要素も影響する
lst[0][0] = 9;

foreach (var x in arr)
    foreach (var y in x)
        Console.WriteLine(y);
9
2
3
4

ConvertAll(全要素の変換)

ConvertAllメソッドは、各要素にメソッドを適用した結果から成る新しいListクラスを作成します。


static string Converter(int n)
{
    return n.ToString();
}

static void Main(string[] args)
{
    var lst1 = new List<int>() { 1, 2, 3 };

    List<string> lst2 = lst1.ConvertAll(Converter);

    //型引数を省略しない場合
    List<string> lst3 = lst1.ConvertAll<string>(Converter);

    //ラムダ式
    List<string> lst4 = lst1.ConvertAll(n => n.ToString());
}

引数には変換処理となるメソッドを適用します。
このメソッドは引数にListクラスの要素の型をひとつ取り、任意のデータ型を返すように定義します。
データ型は同じでも別のデータ型でも構いません。

例ではint型のListクラスからstring型のListクラスを作成しています。
戻り値の要素のデータ型は自動的にメソッドの戻り値のデータ型となりますが、型引数で明示的に指定することもできます。

AsReadOnly(読み取り専用コレクションの取得)

AsReadOnlyメソッドはListクラスを読み取り専用にしたReadOnlyCollection<T>を返します。


var lst = new List<int>() { 1, 2, 3 };

System.Collections.ObjectModel.ReadOnlyCollection<int> roLst 
    = lst.AsReadOnly();

//書き換え不可
//roLst[0] = 0;

//このデータ型でも可
IReadOnlyList aro1 = lst.AsReadOnly();
//型推論
var aro2 = lst.AsReadOnly();

返されるデータ型はSystem.Collections.ObjectModel.ReadOnlyCollection<T>という非常に長いものです。
(TはListの要素のデータ型)
その派生クラスであるIReadOnlyList<T>というデータ型でも受け取れますし、可能なら型推論で受け取りましょう。

書き換え不可なオブジェクトはreadonly定数でも作ることができますが、readonlyは対象が参照型の場合に、その参照先の書き換えまでは防ぐことはできません。
Listクラスは参照型なので、readonlyにしても要素の書き換えはできてしまいます。
AsReadOnlyで返されるコレクションは要素の書き換えも防げます。


class Program
{
    readonly static List<int> lst = new List<int>() {
        1, 2
    };

    static void Main(string[] args)
    {
        //readonlyなListで禁止されるのはListそのものの上書き
        //lst = new List<int>();

        //readonlyなListでも要素の書き換えはできる
        lst[0] = 3;

        var roLst = lst.AsReadOnly();

        //AsReadOnlyで取得したコレクションは要素の書き換えも不可
        //roLst[0] = 4;
    }
}

このメソッドは、外部に公開しなければならない値の不用意な変更を防ぐ場合に使用されます。

GetEnumerator(IEnumeratorの取得)

GetEnumeratorメソッドは、配列のIEnumeratorオブジェクトを取得します。


var lst = new List<int>() { 1, 2, 3 };
System.Collections.IEnumerator enumerator = lst.GetEnumerator();

IEnumeratorに関してはyield文とIEnumerableの項を参照してください。

要素の並べ替え

Sort(要素の並べ替え)

Sortメソッドは要素を昇順で並べ替えます。


var lst = new List<int>() { 0, 3, 12, 7, 1 };

lst.Sort();

foreach (var n in lst)
    Console.Write("{0}, ", n);
0, 1, 3, 7, 12,

戻り値はありません。

要素を降順で並べ替えたい場合はReverseメソッドと組み合わせることで可能です。
(以下で説明する並べ替え用メソッドを使用する方法でも可能です)

メソッドを使用した並べ替え

Sortメソッドは要素並べ替え用のメソッドを使用することで、順序を任意に変更できます。
例えばstring型Listクラスの並べ替えは通常はABC順(あいうえお順)ですが、以下のコードは「文字数が少ない順」「同じ文字数の場合はABC順」というルールで並べ替えをしています。


//Sortメソッドの比較用メソッド
//負数を返すとxが手前になる
//正数を返すとyが手前になる
//ゼロを返すと両者は同じ
static int CompareString(string x, string y)
{
    if (x == null)
    {
        if(y == null)
            return 0;
        return -1;
    }
    else if (y == null)
    {
        return 1;
    }

    if (x.Length < y.Length)
        return -1;
    if (x.Length > y.Length)
        return 1;
    //文字数が同じ場合は通常通り
    return string.Compare(x, y);
}

static void Main(string[] args)
{
    var lst = new List<string>()
        { "Tom", "James", "Michael", "Chris", "Bobby" };

    //通常の並べ替え
    lst.Sort();
    foreach (var s in lst)
        Console.Write("{0}, ", s);
    Console.WriteLine();

    //比較用メソッドを使用して並べ替え
    lst.Sort(CompareString);
    foreach (var s in lst)
        Console.Write("{0}, ", s);

    Console.ReadLine();
}
Bobby, Chris, James, Michael, Tom,
Tom, Bobby, Chris, James, Michael,

並べ替え用メソッドを以下のようにすると、要素を降順で並べ替えることができます。


static int CompareReverse(int x, int y)
{
    //xのほうが大きい場合はxを手前にする
    return x == y ? 0 :
        x > y ? -1 : 1;
}

static int CompareReverse(string x, string y)
{
    //xとyを逆にしてCompareする
    return string.Compare(y, x);
}

static void Main(string[] args)
{
    var lstInt = new List<int>()
        { 5, 7, 11, 2, 9 };
    var lstString = new List<string>()
        { "Tom", "James", "Michael", "Chris", "Bobby" };

    lstInt.Sort(CompareReverse);
    lstString.Sort(CompareReverse);

    foreach (var n in lstInt)
        Console.Write("{0}, ", n);
    Console.WriteLine();

    foreach (var s in lstString)
        Console.Write("{0}, ", s);

    Console.ReadLine();
}
11, 9, 7, 5, 2,
Tom, Michael, James, Chris, Bobby,

Reverse(要素の前後反転)

Reverseメソッドは要素の並びを反転させます。


var lst = new List<int>()
    { 5, 7, 11, 2, 9 };

lst.Reverse();

foreach (var n in lst)
    Console.Write("{0}, ", n);
9, 2, 11, 7, 5,

戻り値はありません。

第一引数、第二引数に数値を指定することで指定の範囲のみ反転させることができます。


var lst = new List<int>()
    { 5, 7, 11, 2, 9 };

//1番目の要素から3つ分を反転
lst.Reverse(1, 3);

foreach (var n in lst)
    Console.Write("{0}, ", n);
5, 2, 11, 7, 9,

降順で並べ替え

Reverseメソッドは降順ではなく前後の反転です。
降順で並べ替えるにはSortメソッドで昇順に並べ替えてからReverseメソッドを適用します。


var lst = new List<int>()
    { 5, 7, 11, 2, 9 };

lst.Sort();
lst.Reverse();

foreach (var n in lst)
    Console.Write("{0}, ", n);
11, 9, 7, 5, 2,

その他、並べ替えメソッドを自分で定義することでも降順で並べ替えが可能です。

検索

Contains(要素の存在判定)

ContainsメソッドはList中の要素に特定の値が存在するかを判定します。


var lst = new List<int>() { 2, 3, 5, 7, 11 };

Console.WriteLine(lst.Contains(7));
Console.WriteLine(lst.Contains(8));
True
False

指定の値が要素内に一つでも存在すれば真を返します。
要素が存在する場所(要素番号)を知りたい場合はIndexOfLastIndexOfメソッドなどを使用します。

IndexOf(要素の検索)

IndexOfメソッドはListから要素を検索し、その要素番号を返します。


var lst = new List<int>() { 2, 3, 5, 7, 11 };

int index1 = lst.IndexOf(7);
int index2 = lst.IndexOf(8);

Console.WriteLine(index1);
Console.WriteLine(index2);
3
-1

検索は先頭の要素から開始し、最初に見つかった要素の番号を返します。
要素が見つからなかった場合は「-1」を返します。

「ある値が存在するか否か」だけを知りたい場合はContainsメソッドを使用してください。

第二引数に検索を開始する要素番号、第三引数に検索する要素数を指定することができます。


var lst = new List<int>() { 0, 3, 12, 7, 1, 0, 6 };

//先頭から「0」を検索
int index1 = lst.IndexOf(0);

//2番目の要素から末尾までで「0」を検索
int index2 = lst.IndexOf(0, 2);

//2番目の要素から3つ分まで「0」を検索
int index3 = lst.IndexOf(0, 2, 3);

Console.WriteLine(index1);
Console.WriteLine(index2);
Console.WriteLine(index3);
0
5
-1

例えばList内に含まれる目的の要素をすべて表示するには以下のようにします。


List<int> lst = new List<int> { 0, 12, 16, 0, 7, 0, 3 };
int index = 0;

//「0」が出現する位置をすべて表示
while ((index = lst.IndexOf(0, index)) >= 0)
{
    Console.WriteLine(index);
    ++index; //見つかった要素の次から検索
}
0
3
5

LastIndexOf(要素の後方検索)

IndexOfメソッドは要素を先頭から検索しますが、後方から検索したい場合はLastIndexOfメソッドを使用します。


var lst = new List<int>() { 0, 3, 12, 7, 1, 0, 6 };

//前方検索
int index = lst.IndexOf(0);

//後方検索
int lastIndex = lst.LastIndexOf(0);

Console.WriteLine(index);
Console.WriteLine(lastIndex);
0
5

検索が後方から行われる以外はIndexOfメソッドと同じです。
第二引数、第三引数を指定して検索範囲を絞れるのも同じです。

戻り値もIndexOfメソッドと同じで要素番号です。
後ろから数えた番号というわけではないので注意してください。

BinarySearch(要素の二分検索)

要素の検索にはIndexOfメソッドを用いますが、BinarySearchメソッドを使用する方法もあります。
BinarySearchメソッドは二分検索という方法で検索を行います。
これは先頭から順に検索するIndexOfメソッドよりも高速な検索が可能です。
ただしBinarySearchメソッドは要素が昇順で並べ替えられている必要があります。
昇順で並んでいることが明らかでない場合はBinarySearchメソッドを使用する前にSortメソッドを適用しておく必要があります。


var lst = new List<int>()
    { 5, 7, 11, 2, 9 };

var item = 7;

lst.Sort();

int index = lst.BinarySearch(item);

foreach (var n in lst)
    Console.Write("{0}, ", n);
Console.WriteLine();
Console.WriteLine("「{0}」は{1}番目", item, index);
2, 5, 7, 9, 11,
「7」は2番目

戻り値は見つかった要素の要素番号です。
見つからなかった場合は負数を返します。

ユーザー定義クラスの比較

ユーザー定義クラスを要素にするListクラスでBinarySearchメソッドを使用するには、要素の型がIComparableインターフェイスを継承しているか、第二引数にIComparerインターフェイスを継承するクラスを指定する必要があります。

詳しくはオブジェクトの比較を参照してください。

Find(条件に合致する要素の取得)

Findメソッドは、指定の条件に合致する要素を取得します。
このメソッドはRemoveAllメソッドと同じく条件判定用のメソッドを使用します。


//引数が10以上なら真を返すメソッド
static bool IsGTE10(int n)
{
    return n >= 10;
}

static void Main(string[] args)
{
    var lst = new List<int>() { 8, 3, 16, 19, 2, 31 };

    //10以上の値の最初の要素を検索
    int find = lst.Find(IsGTE10);

    Console.WriteLine(find);

    Console.ReadLine();
}
16

サンプルコードでは10以上の要素をList内から検索し、最初に見つかった要素を返します。
(要素番号ではなく要素自体を返す)
見つからなかった場合は既定値を返します。
(int型なら「0」)

Findメソッドの仲間

条件判定メソッドを使用して要素を検索するメソッドは他にも存在します。
使い方はFindメソッドと同じなので、具体的な説明は以下のコードを参照してください。


static bool IsGTE10(int n)
{
    return n >= 10;
}

static void Main(string[] args)
{
    var lst = new List<int>() { 8, 3, 16, 19, 2, 31 };

    //最初に見つかった要素を返す
    int find =
        lst.Find(IsGTE10);

    //最後に見つかった要素を返す
    int findLast =
        lst.FindLast(IsGTE10);

    //最初に見つかった要素の要素番号を返す
    int findIndex =
        lst.FindIndex(IsGTE10);

    //最後に見つかった要素の要素番号を返す
    int findLastIndex =
        lst.FindLastIndex(IsGTE10);

    //条件に合致するすべての要素をListで返す
    List<int> findAll =
        lst.FindAll(IsGTE10);

    //条件に合致する要素が存在するかを真偽値で返す
    bool exists =
        lst.Exists(IsGTE10);

    //すべての要素が条件に合致するかを真偽値で返す
    bool trueForAll =
        lst.TrueForAll(IsGTE10);

    Console.Write("検索対象のList: ");
    foreach (var n in lst)
        Console.Write("{0}, ", n);
    Console.WriteLine("\n検索条件: n >= 10\n");

    Console.WriteLine("Find: {0}", find);
    Console.WriteLine("FindLast: {0}", findLast);
    Console.WriteLine("FindIndex: {0}", findIndex);
    Console.WriteLine("FindLastIndex: {0}", findLastIndex);

    Console.Write("FindAll: ");
    foreach (var n in findAll)
        Console.Write("{0}, ", n);
    Console.WriteLine();

    Console.WriteLine("Exists: {0}", exists);
    Console.WriteLine("TrueForAll: {0}", trueForAll);

    Console.ReadLine();
}
検索対象のList: 8, 3, 16, 19, 2, 31,
検索条件: x >= 10

Find: 16
FindLast: 31
FindIndex: 2
FindLastIndex: 5
FindAll: 16, 19, 31,
Exists: True
TrueForAll: False

FindIndexメソッドとFindLastIndexメソッドは、要素が見つからなかった場合は「-1」を返します。
またこれらのメソッドにはオーバーロードが存在します。


static bool IsGTE10(int n)
{
    return n >= 10;
}

static void Main(string[] args)
{
    var lst = new List<int>() { 0, 1, 12, 3, 4, 15 };

    //3番目の要素から検索開始
    int findIndex1 = lst.FindIndex(3, IsGTE10);

    //3番目の要素から2つ分を検索
    int findIndex2 = lst.FindIndex(3, 2, IsGTE10);

    //4番目の要素から検索開始
    int findLastIndex1 = lst.FindLastIndex(4, IsGTE10);

    //4番目の要素から2つ分を検索
    int findLastIndex2 = lst.FindLastIndex(4, 2, IsGTE10);

    Console.WriteLine(findIndex1);
    Console.WriteLine(findIndex2);

    Console.WriteLine(findLastIndex1);
    Console.WriteLine(findLastIndex2);

    Console.ReadLine();
}
5
-1
2
-1

容量

EnsureCapacity(容量の確保)

EnsureCapacityメソッドは、少なくとも指定の要素数を格納できるサイズにListの容量を拡張します。
このメソッドは.NET6以降で使用できます。


var lst = new List<int>() { 1, 2, 3, 4, 5 };

Console.WriteLine(lst.Capacity);

//容量を10に設定
lst.EnsureCapacity(10);
Console.WriteLine(lst.Capacity);

//容量を4に設定
lst.EnsureCapacity(4);
Console.WriteLine(lst.Capacity);
8
16
16

引数の値は最低限確保される容量の指定です。
この値以上の容量が確保されますが、実際のサイズがいくつになるかはコンパイラ次第です。

このメソッドは容量の削除はできません。
容量の削除はCapacityプロパティを変更するか、TrimExcessメソッドを使用します。
なお、Capacityプロパティを直接変更する場合、現在の要素数未満の値を指定すると実行時エラーになりますが、EnsureCapacityメソッドではエラーにはならず容量も変更されません。

TrimExcess(容量の縮小)

TrimExcessメソッドは、Listの不要な容量を削除します。


var lst = new List<int>(10) { 1, 2, 3 };
Console.WriteLine("Capacity: {0}", lst.Capacity);
Console.WriteLine("Count: {0}", lst.Count);
Console.WriteLine();

//未使用の容量を削除
lst.TrimExcess();
Console.WriteLine("Capacity: {0}", lst.Capacity);
Console.WriteLine("Count: {0}", lst.Count);
Capacity: 10
Count: 3

Capacity: 3
Count: 3

このメソッドは空き容量が10%未満の場合は縮小されません。
正確には(int)(Capacity * 0.9) > Countが真の場合に削除処理が実行されます。


var lst = new List<int>() { 1, 2, 3 };
Console.WriteLine("Capacity: {0}", lst.Capacity);
Console.WriteLine("Count: {0}", lst.Count);
Console.WriteLine("Threshold: {0}", (int)(lst.Capacity * 0.9));
Console.WriteLine();

lst.TrimExcess();
Console.WriteLine("Capacity: {0}", lst.Capacity);
Console.WriteLine("Count: {0}", lst.Count);
Console.WriteLine("Threshold: {0}", (int)(lst.Capacity * 0.9));
//ThresholdとCountが同じ(空き容量が10%未満)なので縮小されない
Capacity: 4
Count: 3
Threshold: 3

Capacity: 4
Count: 3
Threshold: 3