List<T>.Contains() / IndexOf()
| 対応: | C# 2.0(2005) |
|---|
リスト内に指定した要素が含まれるか確認する『Contains()』と、要素が最初に現れるインデックスを返す『IndexOf()』メソッドです。
構文
using System.Collections.Generic; // 指定した要素がリスト内に存在する場合は true を返します list.Contains(T item) // 指定した要素が最初に現れるインデックスを返します。見つからない場合は -1 を返します list.IndexOf(T item) // startIndex から検索を開始します list.IndexOf(T item, int startIndex) // 指定した要素が最後に現れるインデックスを返します list.LastIndexOf(T item)
メソッド一覧
| メソッド | 概要 |
|---|---|
| Contains(T item) | リストに item が含まれる場合は true を返します。内部で順番に比較するため O(n) の処理です。 |
| IndexOf(T item) | item が最初に現れるインデックスを返します。見つからない場合は -1 を返します。 |
| IndexOf(T item, int startIndex) | startIndex から検索を開始し、最初に一致した要素のインデックスを返します。 |
| LastIndexOf(T item) | item が最後に現れるインデックスを返します。見つからない場合は -1 を返します。 |
サンプルコード
Contains() で要素の存在チェックを行い、IndexOf() でインデックスを取得します。
Program.cs
using System;
using System.Collections.Generic;
List<string> languages = new List<string> { "C#", "Java", "Python", "Java", "Go" };
Console.WriteLine(languages.Contains("Python")); // True
Console.WriteLine(languages.Contains("Swift")); // False
if (languages.Contains("C#"))
{
Console.WriteLine("C# はリストに含まれています。");
}
Console.WriteLine(languages.IndexOf("Java")); // 1
Console.WriteLine(languages.IndexOf("Swift")); // -1
Console.WriteLine(languages.LastIndexOf("Java")); // 3
dotnet run True False C# はリストに含まれています。 1 -1 3
IndexOf() で重複要素を検出する
IndexOf() と LastIndexOf() の両方を使うと、同じ値が複数存在するかどうかを確認できます。インデックスが異なれば重複しています。
DuplicateCheck.cs
using System;
using System.Collections.Generic;
List<string> languages = new List<string> { "C#", "Java", "Python", "Java", "Go" };
int firstIdx = languages.IndexOf("Java");
int lastIdx = languages.LastIndexOf("Java");
if (firstIdx != lastIdx)
{
Console.WriteLine($"Java は複数回存在します(インデックス {firstIdx} と {lastIdx})。");
}
// startIndex を指定して次の出現位置を探す
int next = languages.IndexOf("Java", firstIdx + 1);
Console.WriteLine($"次の Java のインデックス: {next}"); // 3
dotnet run Java は複数回存在します(インデックス 1 と 3)。 次の Java のインデックス: 3
実践パターン: 選択肢の入力バリデーション
Contains() を使うと、ユーザーの入力が有効な選択肢かどうかを簡潔に確認できます。
ValidateSample.cs
using System;
using System.Collections.Generic;
List<string> validChoices = new List<string> { "開始", "設定", "終了" };
string[] inputs = { "開始", "ヘルプ", "終了" };
foreach (string input in inputs)
{
if (validChoices.Contains(input))
{
Console.WriteLine($"'{input}' は有効な選択肢です。");
}
else
{
Console.WriteLine($"'{input}' は無効な選択肢です。");
}
}
dotnet run '開始' は有効な選択肢です。 'ヘルプ' は無効な選択肢です。 '終了' は有効な選択肢です。
よくあるミス
よくあるミス: 頻繁な検索に List を使うとパフォーマンスが低下する
Contains() と IndexOf() は O(n)(リストを先頭から順番に探す)の処理です。要素数が多く頻繁に検索する場合は、O(1) で検索できる HashSet<T> や Dictionary<TKey, TValue> を使います。
using System; using System.Collections.Generic; // NG: 大量データへの頻繁な検索に List の Contains を使う List<int> bigList = new List<int>(); for (int i = 0; i < 100000; i++) bigList.Add(i); // Contains() は毎回リストの先頭から順番に探す(O(n)) Console.WriteLine(bigList.Contains(99999)); // True(遅い)
修正後は次の通りです。
using System; using System.Collections.Generic; // OK: HashSet<T> を使えば O(1) で検索できる HashSet<int> bigSet = new HashSet<int>(); for (int i = 0; i < 100000; i++) bigSet.Add(i); Console.WriteLine(bigSet.Contains(99999)); // True(速い)
dotnet run True True
要素の順序が不要で存在チェックだけ必要な場合は HashSet<T> が適しています。詳細は『HashSet<T>』を参照してください。
概要
Contains() と IndexOf() はどちらも内部でリストを先頭から順番に走査するため、要素数に比例した処理時間(O(n))がかかります。頻繁な検索が必要な場合は『Dictionary<TKey, TValue>』や HashSet<T> の使用を検討してください。これらは O(1) で検索できます。
リストの並べ替えやループ処理には『List<T>.Sort() / Reverse() / ForEach()』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。