C# RemoveRangeの使い方を徹底解説|Listから複数要素を削除する方法と注意点

はじめに

C#でList<T>から連続する複数の要素を削除したい場合は、RemoveRangeメソッドが便利です。削除を開始するインデックスと要素数を指定するだけで、リストの先頭・途中・末尾にある複数要素をまとめて削除できます。

ただし、RemoveRangeでは削除範囲を正しく指定しなければなりません。インデックスや要素数がリストの範囲を超えると例外が発生するほか、削除後は後続要素のインデックスが変化します。

この記事では、C#のRemoveRangeの基本構文から、例外を防ぐ方法、条件に一致する要素の削除、ほかの削除メソッドとの違い、実践的なコード例まで詳しく解説します。

1. C#のRemoveRangeとは

1-1. Listから指定範囲の要素を一括削除するメソッド

RemoveRangeは、List<T>から連続する範囲の要素を一括削除するメソッドです。

たとえば、次のリストからインデックス1を起点に3件削除できます。

var numbers = new List<int> { 10, 20, 30, 40, 50 };

numbers.RemoveRange(1, 3);

Console.WriteLine(string.Join(", ", numbers));// 10, 50

削除された要素は、インデックス1、2、3にあった203040です。

RemoveRangeでは値を指定するのではなく、「何番目から何件削除するか」を指定します。

1-2. RemoveRangeが使えるコレクション型

一般的なC#プログラムでRemoveRangeを使用する対象は、System.Collections.Generic.List<T>です。

List<string> names = new List<string>{"Alice","Bob","Carol"};

names.RemoveRange(0, 2);

非ジェネリックコレクションであるArrayListにも同名のRemoveRangeがありますが、現在のC#では型安全なList<T>を使うのが一般的です。

一方、次の型ではList<T>と同じようにRemoveRangeを呼び出すことはできません。

  • 配列

  • IEnumerable<T>

  • ICollection<T>

  • LinkedList<T>

  • HashSet<T>

変数の実体がList<T>であっても、変数の型がIList<T>などの場合は、インターフェースにRemoveRangeが定義されていないため直接呼び出せません。

IList<int> numbers = new List<int> { 1, 2, 3, 4 };

// numbers.RemoveRange(1, 2);// コンパイルエラー

1-3. RemoveRangeを使うメリット

RemoveRangeの主なメリットは、連続する複数要素を1回のメソッド呼び出しで削除できることです。

numbers.RemoveRange(100, 500);

RemoveAtを何度も呼び出すコードと比べて、次の利点があります。

  • 削除する範囲が明確になる

  • コードが短く読みやすい

  • 要素を詰め直す処理の回数を減らせる

  • インデックスの変化によるミスを防ぎやすい

連続した範囲を削除する場合は、原則としてRemoveAtの繰り返しよりRemoveRangeが適しています。

2. RemoveRangeの基本構文と引数

2-1. RemoveRange(index, count)の書き方

RemoveRangeの基本構文は次のとおりです。

list.RemoveRange(index, count);

引数の意味は次のようになります。

引数意味
index削除を開始する位置
count削除する要素数

たとえば、インデックス2から4件削除する場合は次のように記述します。

list.RemoveRange(2, 4);

2-2. indexで削除開始位置を指定する

第1引数のindexには、削除を開始する要素のインデックスを指定します。

var fruits = new List<string>{"Apple",   // 0"Banana",  // 1"Orange",  // 2"Grape"    // 3};

fruits.RemoveRange(1, 2);

このコードではインデックス1のBananaから削除が始まり、BananaOrangeが削除されます。

実行後のリストは次のとおりです。

Apple, Grape

2-3. countで削除する要素数を指定する

第2引数のcountには、削除する要素数を指定します。

countは終了位置ではない点に注意してください。

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

values.RemoveRange(2, 3);

インデックス2から3件削除するため、削除されるのは234です。

インデックス2からインデックス3までを削除したい場合、削除件数は2件なので次のように指定します。

values.RemoveRange(2, 2);

2-4. 戻り値がないことに注意する

RemoveRangeの戻り値はvoidです。削除された要素や削除件数は返されません。

次のような代入はできません。

// コンパイルエラーvar removed = values.RemoveRange(1, 2);

削除された要素を取得したい場合は、削除前にGetRangeを使用します。

var values = new List<int> { 10, 20, 30, 40, 50 };

List<int> removed = values.GetRange(1, 3);values.RemoveRange(1, 3);

Console.WriteLine(string.Join(", ", removed));// 20, 30, 40

3. RemoveRangeの基本的な使い方

3-1. Listから複数の要素を削除するサンプル

次の例では、文字列のリストから連続する3要素を削除しています。

var colors = new List<string>{"Red","Blue","Green","Yellow","Black"};

colors.RemoveRange(1, 3);

Console.WriteLine(string.Join(", ", colors));// Red, Black

インデックス1から3件削除したため、BlueGreenYellowが削除されます。

3-2. リストの先頭から複数要素を削除する

リストの先頭から削除する場合、indexには0を指定します。

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

numbers.RemoveRange(0, 2);

Console.WriteLine(string.Join(", ", numbers));// 3, 4, 5

先頭の2件を処理済みデータとして取り除く場合などに使用できます。

3-3. リストの途中から複数要素を削除する

途中から削除する場合は、削除開始位置をindexに指定します。

var numbers = new List<int> { 10, 20, 30, 40, 50, 60 };

numbers.RemoveRange(2, 2);

Console.WriteLine(string.Join(", ", numbers));// 10, 20, 50, 60

インデックス2から2件、つまり3040が削除されます。

3-4. リストの末尾から複数要素を削除する

末尾から一定件数を削除する場合、削除開始位置はCount - 削除件数で求められます。

var numbers = new List<int> { 1, 2, 3, 4, 5 };int removeCount = 2;

numbers.RemoveRange(numbers.Count - removeCount, removeCount);

Console.WriteLine(string.Join(", ", numbers));// 1, 2, 3

removeCountCountを超える可能性がある場合は、事前チェックが必要です。

if (removeCount >= 0 && removeCount <= numbers.Count){numbers.RemoveRange(numbers.Count - removeCount, removeCount);}

3-5. リスト内の全要素を削除する

RemoveRangeで全要素を削除する場合は、先頭からCount件を指定します。

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

numbers.RemoveRange(0, numbers.Count);

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

ただし、単純に全要素を削除する目的であれば、Clearのほうが意図を理解しやすいコードになります。

numbers.Clear();

4. 削除範囲を正しく指定する方法

4-1. Listのインデックスは0から始まる

List<T>のインデックスは0から始まります。

要素:        A  B  C  D  Eインデックス: 0  1  2  3  4

3番目の要素を起点に削除したい場合、index2です。

list.RemoveRange(2, count);

「3番目だから3」と指定すると、4番目の要素から削除されるため注意してください。

4-2. 削除可能な範囲をCountプロパティで確認する

削除範囲が有効であるためには、基本的に次の条件を満たす必要があります。

index >= 0count >= 0index + count <= list.Count

オーバーフローを避けて判定するなら、次の形式が安全です。

bool isValid =index >= 0 &&count >= 0 &&index <= list.Count &&count <= list.Count - index;

有効な場合だけ削除します。

if (isValid){list.RemoveRange(index, count);}

4-3. 指定位置から末尾まで削除する計算方法

指定したインデックスから末尾まで削除する場合、countCount - indexで求めます。

var numbers = new List<int> { 10, 20, 30, 40, 50 };int startIndex = 2;

numbers.RemoveRange(startIndex, numbers.Count - startIndex);

Console.WriteLine(string.Join(", ", numbers));// 10, 20

startIndexが0以上かつCount以下であることを確認してから実行します。

if (startIndex >= 0 && startIndex <= numbers.Count){numbers.RemoveRange(startIndex, numbers.Count - startIndex);}

startIndex == Countの場合、削除件数は0となり、リストは変更されません。

4-4. 条件によってindexとcountを動的に決める方法

外部入力や検索結果から削除範囲を決める場合は、範囲を正規化してからRemoveRangeを呼び出します。

int requestedIndex = 3;int requestedCount = 10;

int index = Math.Clamp(requestedIndex, 0, list.Count);int count = Math.Clamp(requestedCount, 0, list.Count - index);

list.RemoveRange(index, count);

このコードでは、削除開始位置と件数がリストの範囲内に収まるよう調整されます。

ただし、不正な入力を自動補正するとバグを見逃す場合があります。入力値が不正ならエラーにしたい処理では、明示的に例外を投げる方法が適しています。

if (requestedIndex < 0 || requestedIndex > list.Count){throw new ArgumentOutOfRangeException(nameof(requestedIndex));}

if (requestedCount < 0 ||requestedCount > list.Count - requestedIndex){throw new ArgumentOutOfRangeException(nameof(requestedCount));}

list.RemoveRange(requestedIndex, requestedCount);

4-5. countに0を指定した場合の動作

countに0を指定すると、要素は削除されません。

var numbers = new List<int> { 1, 2, 3 };

numbers.RemoveRange(1, 0);

Console.WriteLine(string.Join(", ", numbers));// 1, 2, 3

indexCountを指定し、countを0にすることも可能です。

numbers.RemoveRange(numbers.Count, 0);

一方、countが0でも、indexが負数またはCountを超えていれば例外になります。

5. RemoveRangeで発生する例外と対処法

5-1. indexが負数の場合に発生するArgumentOutOfRangeException

indexに負数を指定すると、ArgumentOutOfRangeExceptionが発生します。

var numbers = new List<int> { 1, 2, 3 };

numbers.RemoveRange(-1, 1);

削除開始位置を検索で取得する場合は特に注意が必要です。FindIndexIndexOfは、要素が見つからなければ-1を返します。

int index = numbers.FindIndex(x => x == 100);

if (index >= 0){numbers.RemoveRange(index, 1);}

5-2. countが負数の場合に発生するArgumentOutOfRangeException

countに負数を指定した場合も、ArgumentOutOfRangeExceptionが発生します。

numbers.RemoveRange(0, -1);

たとえば、終了位置から削除件数を計算する場合、開始位置と終了位置が逆になっていると負数になる可能性があります。

int count = endIndex - startIndex + 1;

実行前にendIndex >= startIndexであることを確認しましょう。

5-3. indexとcountがListの範囲を超えた場合のArgumentException

indexcountがそれぞれ0以上でも、組み合わせた削除範囲がリストを超えるとArgumentExceptionが発生します。

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

numbers.RemoveRange(3, 3);

インデックス3から削除できるのは、インデックス3と4の2件だけです。3件を指定すると範囲外になります。

次の条件で確認できます。

if (index <= numbers.Count &&count <= numbers.Count - index){numbers.RemoveRange(index, count);}

5-4. 空のListにRemoveRangeを実行する際の注意点

空のリストに対してRemoveRange(0, 0)を実行しても例外は発生しません。

var numbers = new List<int>();

numbers.RemoveRange(0, 0);

しかし、1件以上削除しようとすると例外になります。

numbers.RemoveRange(0, 1);

全要素を削除するコードとして次の形式を使っている場合、空のリストでも安全に動作します。

numbers.RemoveRange(0, numbers.Count);

5-5. 範囲チェックを行って例外を防ぐコード例

繰り返し使用する場合は、範囲チェックをメソッドにまとめると便利です。

static bool TryRemoveRange<T>(List<T> list,int index,int count){ArgumentNullException.ThrowIfNull(list);

if (index &lt; 0 ||count &lt; 0 ||index &gt; list.Count ||count &gt; list.Count - index){return false;}list.RemoveRange(index, count);return true;

}

使用例は次のとおりです。

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

bool removed = TryRemoveRange(numbers, 2, 2);

Console.WriteLine(removed);// True

Console.WriteLine(string.Join(", ", numbers));// 1, 2, 5

範囲が不正な場合はfalseを返し、リストを変更しません。

6. 条件に一致する複数要素を削除する方法

6-1. RemoveRangeでは値や条件を直接指定できない

RemoveRangeで指定できるのは、削除開始インデックスと削除件数だけです。

次のように「偶数をすべて削除する」といった条件は直接指定できません。

// このようなRemoveRangeの使い方はできない// numbers.RemoveRange(x => x % 2 == 0);

条件に一致する要素を削除する場合は、RemoveAllなどを使用します。

6-2. RemoveAllを使って条件に一致する要素を削除する

RemoveAllは、指定した条件に一致するすべての要素を削除します。

var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

int removedCount = numbers.RemoveAll(x => x % 2 == 0);

Console.WriteLine(string.Join(", ", numbers));// 1, 3, 5

Console.WriteLine(removedCount);// 3

RemoveAllは削除件数をintで返します。この点は戻り値がないRemoveRangeとの違いです。

6-3. FindIndexで削除開始位置を取得してRemoveRangeを使う

特定の条件に一致した位置から、連続する一定件数を削除したい場合は、FindIndexRemoveRangeを組み合わせます。

var numbers = new List<int>{10, 20, 30, 40, 50, 60};

int index = numbers.FindIndex(x => x >= 30);

if (index >= 0){int count = Math.Min(3, numbers.Count - index);numbers.RemoveRange(index, count);}

Console.WriteLine(string.Join(", ", numbers));// 10, 20, 60

条件に一致する連続区間を削除する場合は、開始位置を取得した後に連続件数を数えます。

var numbers = new List<int>{1, 2, 10, 20, 30, 3, 4};

int startIndex = numbers.FindIndex(x => x >= 10);

if (startIndex >= 0){int count = 0;

while (startIndex + count &lt; numbers.Count &amp;&amp;numbers<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[startIndex + count]</span> &gt;= 10){count++;}numbers.RemoveRange(startIndex, count);

}

6-4. 連続していない要素を安全に削除する方法

削除対象が連続していない場合は、RemoveRangeよりRemoveAllが適しています。

numbers.RemoveAll(x => x < 0);

インデックスの一覧を使って削除する必要がある場合は、大きいインデックスから順にRemoveAtを呼び出します。

var values = new List<string>{"A", "B", "C", "D", "E"};

var indexesToRemove = new List<int> { 1, 3 };

foreach (int index in indexesToRemove.OrderByDescending(x => x)){values.RemoveAt(index);}

Console.WriteLine(string.Join(", ", values));// A, C, E

前から削除すると後続要素のインデックスが変わるため、意図しない要素を削除する可能性があります。

6-5. LINQのWhereで削除対象を除外した新しいListを作る方法

元のリストを変更せず、条件に一致しない要素だけを持つ新しいリストを作る場合は、LINQのWhereを使います。

var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

List<int> oddNumbers = numbers.Where(x => x % 2 != 0).ToList();

Console.WriteLine(string.Join(", ", oddNumbers));// 1, 3, 5

元のnumbersは変更されません。

大量データでは新しいリストを作るためのメモリが必要になりますが、元データを保持したい場合や、副作用を避けたい場合に適しています。

7. RemoveRangeとほかの削除メソッドの違い

7-1. Removeとの違い|指定した値を1件削除

Removeは、指定した値と等しい最初の要素を削除します。

var numbers = new List<int> { 1, 2, 2, 3 };

bool removed = numbers.Remove(2);

Console.WriteLine(string.Join(", ", numbers));// 1, 2, 3

同じ値が複数ある場合でも、削除されるのは最初の1件だけです。

7-2. RemoveAtとの違い|指定位置の要素を1件削除

RemoveAtは、指定したインデックスの要素を1件削除します。

var numbers = new List<int> { 10, 20, 30 };

numbers.RemoveAt(1);

Console.WriteLine(string.Join(", ", numbers));// 10, 30

削除対象が1件だけならRemoveAt、連続する複数件ならRemoveRangeが適しています。

7-3. RemoveAllとの違い|条件に一致する要素を一括削除

RemoveAllは、条件に一致する要素をすべて削除します。

numbers.RemoveAll(x => x >= 100);

対象要素がリスト内で連続している必要はありません。

RemoveRangeは位置と件数、RemoveAllは条件を基準に削除するメソッドです。

7-4. Clearとの違い|すべての要素を削除

Clearはリスト内の全要素を削除します。

numbers.Clear();

次のRemoveRangeと結果は同じです。

numbers.RemoveRange(0, numbers.Count);

全件削除が目的なら、通常はClearを選ぶと意図が明確です。

7-5. 用途別の削除メソッドの選び方

目的適したメソッド
指定した値を1件削除Remove
指定位置の1件を削除RemoveAt
連続する複数件を削除RemoveRange
条件に一致する全要素を削除RemoveAll
全要素を削除Clear
元のリストを残して除外後のリストを作成WhereToList

削除条件が「位置」なのか「値」なのか「条件」なのかを整理すると、適切なメソッドを選びやすくなります。

8. RemoveRangeを使う際の注意点

8-1. 削除後は後続要素のインデックスが変わる

RemoveRangeを実行すると、削除範囲より後ろにあった要素が前に詰められます。

var values = new List<string>{"A", // 0"B", // 1"C", // 2"D", // 3"E"  // 4};

values.RemoveRange(1, 2);

実行後は次の状態になります。

A: 0D: 1E: 2

削除前に記録したインデックスを、そのまま削除後のリストに使用しないよう注意してください。

8-2. foreachループ中にListを変更してはいけない

foreachでリストを列挙している途中にRemoveRangeなどでリストを変更すると、通常はInvalidOperationExceptionが発生します。

foreach (int number in numbers){if (number == 3){numbers.RemoveRange(0, 1);}}

条件削除ならRemoveAllを使用するか、削除対象を先に調べてからループの外で変更します。

int index = numbers.FindIndex(x => x == 3);

if (index >= 0){numbers.RemoveRange(0, index + 1);}

8-3. 複数回削除する場合は後ろから処理する

複数の削除範囲を処理する場合は、開始インデックスが大きい範囲から削除します。

var ranges = new[]{(Index: 1, Count: 2),(Index: 5, Count: 2)};

foreach (var range in ranges.OrderByDescending(x => x.Index)){list.RemoveRange(range.Index, range.Count);}

後ろの要素を先に削除すれば、前方にある削除範囲のインデックスは変化しません。

削除範囲が重複している場合は、事前に範囲を統合する必要があります。

8-4. 元のListが直接変更される

RemoveRangeは、呼び出し元のList<T>を直接変更します。

var original = new List<int> { 1, 2, 3, 4 };var another = original;

another.RemoveRange(0, 2);

Console.WriteLine(string.Join(", ", original));// 3, 4

originalanotherは同じリストを参照しているため、両方から見える内容が変わります。

元のリストを残したい場合はコピーを作成します。

var copied = new List<int>(original);copied.RemoveRange(0, 2);

8-5. 配列ではRemoveRangeを使用できない

配列は作成後に要素数を変更できないため、RemoveRangeは使用できません。

int[] numbers = { 1, 2, 3, 4, 5 };

// numbers.RemoveRange(1, 2);// コンパイルエラー

削除可能なリストに変換する方法があります。

var list = numbers.ToList();list.RemoveRange(1, 2);

int[] result = list.ToArray();

新しい配列を作るだけなら、LINQで削除範囲以外を取得する方法もあります。

int index = 1;int count = 2;

int[] result = numbers.Take(index).Concat(numbers.Skip(index + count)).ToArray();

9. RemoveRangeの実践的な使用例

9-1. ページング処理で不要な範囲を削除する

全データから指定ページの要素だけを残す例です。

var items = Enumerable.Range(1, 100).ToList();

int pageNumber = 3;int pageSize = 10;int offset = (pageNumber - 1) * pageSize;

if (offset >= 0 && offset < items.Count){int actualSize = Math.Min(pageSize, items.Count - offset);

int afterPageIndex = offset + actualSize;items.RemoveRange(afterPageIndex,items.Count - afterPageIndex);items.RemoveRange(0, offset);

}else{items.Clear();}

後方を先に削除してから前方を削除するのがポイントです。

ただし、元データを残すページング処理では、一般にSkipTakeのほうが分かりやすくなります。

List<int> pageItems = items.Skip(offset).Take(pageSize).ToList();

9-2. 指定件数を超えた古いデータを削除する

古いデータが先頭、新しいデータが末尾に並んでいるリストで、最新100件だけを残す例です。

int maxCount = 100;

if (logs.Count > maxCount){int removeCount = logs.Count - maxCount;logs.RemoveRange(0, removeCount);}

ログ履歴、検索履歴、通知履歴などの件数制限に利用できます。

9-3. 開始位置と終了位置を指定して削除する

開始インデックスと終了インデックスを両方含めて削除する場合、件数は次の式で求めます。

count = endIndex - startIndex + 1

コード例は次のとおりです。

int startIndex = 2;int endIndex = 5;

if (startIndex >= 0 &&endIndex >= startIndex &&endIndex < list.Count){int count = endIndex - startIndex + 1;list.RemoveRange(startIndex, count);}

終了位置を含めない仕様にする場合は、count = endIndex - startIndexです。仕様を混同しないようにしてください。

9-4. 特定区間だけをListに残す

インデックス2から4件だけを残す例です。

var numbers = new List<int>{10, 20, 30, 40, 50, 60, 70};

int startIndex = 2;int keepCount = 4;

if (startIndex >= 0 &&keepCount >= 0 &&startIndex <= numbers.Count &&keepCount <= numbers.Count - startIndex){int afterKeepIndex = startIndex + keepCount;

numbers.RemoveRange(afterKeepIndex,numbers.Count - afterKeepIndex);numbers.RemoveRange(0, startIndex);

}

Console.WriteLine(string.Join(", ", numbers));// 30, 40, 50, 60

この用途では、元のリストを変更する必要がなければGetRangeのほうが簡潔です。

List<int> selected = numbers.GetRange(startIndex, keepCount);

9-5. 文字列や独自クラスのListから複数要素を削除する

RemoveRangeは、数値だけでなく文字列や独自クラスのList<T>でも使用できます。

文字列の例です。

var names = new List<string>{"Alice","Bob","Carol","Dave"};

names.RemoveRange(1, 2);

Console.WriteLine(string.Join(", ", names));// Alice, Dave

独自クラスの例です。

public class Product{public int Id { get; init; }public string Name { get; init; } = "";}
var products = new List<Product>{new() { Id = 1, Name = "Keyboard" },new() { Id = 2, Name = "Mouse" },new() { Id = 3, Name = "Monitor" },new() { Id = 4, Name = "Printer" }};

products.RemoveRange(1, 2);

foreach (Product product in products){Console.WriteLine(product.Name);}

実行結果は次のとおりです。

KeyboardPrinter

10. RemoveRangeの処理速度とパフォーマンス

10-1. RemoveAtを繰り返す場合との違い

連続する複数要素を削除する場合、RemoveAtを繰り返すよりRemoveRangeを使用するほうが効率的です。

次のコードでは、先頭要素を1000回削除するたびに後続要素の移動が発生します。

for (int i = 0; i < 1000; i++){list.RemoveAt(0);}

RemoveRangeなら、削除と後続要素の移動をまとめて行えます。

list.RemoveRange(0, 1000);

10-2. 削除後に要素を詰め直す処理コスト

List<T>は内部的に連続した領域へ要素を保持します。途中の範囲を削除すると、その後ろにある要素を前方へ移動する必要があります。

そのため、一般に次の傾向があります。

  • 末尾の削除は移動する後続要素が少ない

  • 先頭の削除は多くの後続要素を移動する

  • 削除範囲が同じでも、開始位置によって実際の処理量が変わる

頻繁に先頭要素を削除する用途では、Queue<T>など別のコレクションが適している場合があります。

10-3. 大量データを削除するときの使い分け

大量データを削除するときは、削除対象の性質に応じて使い分けます。

連続範囲を削除する場合はRemoveRangeです。

list.RemoveRange(index, count);

条件に一致する要素を削除する場合はRemoveAllです。

list.RemoveAll(item => item.IsDeleted);

元データを残して対象外の要素だけを取得する場合はLINQを使用します。

var filtered = list.Where(item => !item.IsDeleted).ToList();

多数の範囲を個別に削除する場合は、範囲を統合してRemoveRangeの呼び出し回数を減らすことも検討しましょう。

10-4. 元データを残したい場合はGetRangeやLINQを検討する

RemoveRangeは元のリストを直接変更します。

元データを保持したまま一部の範囲を取得する場合は、GetRangeを使用できます。

List<int> selected = source.GetRange(index, count);

条件やページ単位で取得する場合は、LINQも便利です。

List<int> selected = source.Skip(index).Take(count).ToList();

GetRangeToListで作られるのは別のリストですが、参照型の要素そのものは複製されません。要素のプロパティを変更すると、元リスト内の同じオブジェクトにも影響する可能性があります。

11. RemoveRangeに関するよくある質問

11-1. RemoveRangeで末尾まで削除するにはどうする?

削除開始位置をindexとすると、削除件数はlist.Count - indexです。

if (index >= 0 && index <= list.Count){list.RemoveRange(index, list.Count - index);}

11-2. RemoveRangeで条件に一致する要素を削除できる?

RemoveRangeに条件式を直接指定することはできません。

条件に一致する要素をすべて削除する場合はRemoveAllを使用します。

list.RemoveAll(x => x.Status == "Deleted");

条件に一致した位置から一定件数を削除する場合は、FindIndexRemoveRangeを組み合わせます。

11-3. RemoveRangeで配列の要素を削除できる?

配列にはRemoveRangeがありません。配列は要素数が固定されているためです。

List<T>に変換して削除するか、必要な要素を持つ新しい配列を作ります。

var list = array.ToList();list.RemoveRange(index, count);array = list.ToArray();

11-4. RemoveRangeで削除した要素を取得できる?

RemoveRangeには戻り値がないため、削除した要素は取得できません。

必要な場合は、削除前にGetRangeで保存します。

List<T> removedItems = list.GetRange(index, count);list.RemoveRange(index, count);

11-5. RemoveRangeとGetRangeは何が違う?

RemoveRangeは指定範囲を元のリストから削除します。

list.RemoveRange(index, count);

GetRangeは指定範囲を新しいList<T>として取得し、元のリストは変更しません。

List<T> range = list.GetRange(index, count);

削除が目的ならRemoveRange、抽出が目的ならGetRangeを使用します。

11-6. RemoveRangeを実行しても要素が削除されない原因は?

代表的な原因は、countに0を指定していることです。

list.RemoveRange(index, 0);

このコードでは何も削除されません。

また、元のリストではなくコピーに対して実行している可能性もあります。

var copied = new List<int>(original);copied.RemoveRange(0, 2);

この場合、originalは変更されません。

LINQのToListで作成したリストも元とは別のリストです。

var copied = original.Where(x => true).ToList();copied.RemoveRange(0, 2);

デバッガーで次の項目を確認すると原因を見つけやすくなります。

  • indexの値

  • countの値

  • 実行前後のCount

  • 操作対象の変数

  • 元リストとコピーのどちらを参照しているか