【C#】List検索メソッド(Find・FindAll・FindIndex・FirstOrDefault)を完全攻略!!

悩んでる人

C#のListって検索メソッドがいっぱいあって、どれを使えばいいか全然わからない…

悩んでる人

FindとFindAll、FindIndexって何が違うの?FirstOrDefaultとはどう使い分けるの?


C#のListには検索メソッドがたくさん用意されていて、最初は何を使えばいいか迷いますよね。

おしけん

実は、それぞれのメソッドには明確な「使いどころ」があります。

本記事では、C#のList.Find()の基本的な使い方から、FindAll・FindIndex・FirstOrDefaultとの違いまで、サンプルコードと図解でわかりやすく解説します。

「なんとなく動くコードは書けるけど、これで合ってるか不安…」という方もぜひ参考にしてみてください!

この記事でわかること
  • List.Find() の基本的な書き方とラムダ式の読み方
  • Find / FindAll / FindIndex / FindLast の違い
  • 見つからない場合の戻り値と注意点
  • カスタムクラスのリストを検索する実践例
  • FirstOrDefault との使い分けポイント
この記事を書いた人
  • システムエンジニア10年目
  • 会社員3年⇒フリーランス7年目
  • 保険系 / 物流系 / 鉄道系 / 小売系などのシステム開発に従事
  • プログラミング講師
目次

List.Find()とは?基本を図解でおさえよう

List.Find() は、リストの中から条件に合う最初の要素を1件だけ返すメソッドです。

先頭の要素から順番に確認していき、条件を満たした瞬間にそこで検索をストップします。

おしけん

「リストの中から条件に合う最初の1件だけ返す」のがFindメソッドです。全件ほしい場合はFindAll()を使います!

List<T> クラスが持つメソッドなので、引数には Predicate\(条件を判定するデリゲート)を渡します。

実際のコードではラムダ式を使うのが一般的なので、その書き方も含めて次のセクションで解説します。

Find() の基本的な書き方

数値リストから検索する

using System.Collections.Generic;

var list = new List<int> { 1, 2, 3, 7, 8, 9 };

// 偶数を前から検索して、最初に見つかった1件を返す
int result = list.Find(n => n % 2 == 0);

Console.WriteLine(result); // 出力:2
実行結果

2

ラムダ式 n => n % 2 == 0 の意味は「要素nが偶数かどうかを返す」です。

条件が true になった最初の要素が返されるので、8は返されない点に注意しましょう。

おしけん

ラムダ式 => の左が「要素」、右が「条件式」と覚えれば読めるようになりますよ!

文字列リストから検索する

var fruits = new List<string> { "りんご", "バナナ", "オレンジ", "メロン" };

// 4文字以上の文字列を前から検索
string result = fruits.Find(s => s.Length >= 4);

Console.WriteLine(result); // 出力:オレンジ
実行結果

オレンジ

ポイント

Findメソッドは先頭から順番に検索するため、計算量は O(n) です。リストが大きいほど検索時間が伸びます。

要素数が多く、要素が昇順に並んでいる場合は BinarySearch() の使用も検討しましょう。

見つからない場合の戻り値と注意点

Findメソッドは要素が見つからなかった場合、型の既定値(default value) を返します。

参照型(stringやクラス)なら null、数値型なら 0 が返ってくるため、必ずnullチェックを行いましょう。

リストの型見つかった場合見つからない場合
List<int>(数値)その値0(型の既定値)
List<string>(文字列)その文字列null
List<クラス>(参照型)そのオブジェクトnull
List<構造体>(値型)その構造体ゼロ初期化した構造体
var fruits = new List<string> { "りんご", "バナナ" };

string? result = fruits.Find(s => s == "みかん");

// nullチェックを必ず行う
if (result != null)
{
    Console.WriteLine($"見つかりました:{result}");
}
else
{
    Console.WriteLine("見つかりませんでした");
}
実行結果

見つかりませんでした

注意:数値型はnullチェックだけでは不十分

数値型のリストで値 0 が存在する場合、「見つからなかった」のか「0が見つかった」のかを区別できません。

このケースでは FindIndex() を使い、インデックスが -1 かどうかで判定するのがベターです。

悩んでる人

数値のリストで0が戻ってきたとき、見つからなかったのか、実際に0があるのか区別できないの?

おしけん

その通りです!そんなときはFindIndex()を使って戻り値が-1かどうかを確認しましょう!

FindAll():条件に合う全件を取得

FindAll() は、条件に合う要素を全件取得したいときに使います。

戻り値は List<T> なので、そのままforeachでループ処理できて便利です。

インフォグラフィック:Find() vs FindAll() の違い
メソッド取得件数戻り値
Find()最初の1件のみT型の要素
FindAll()全件List\<T>
var numbers = new List<int> { 1, 2, 3, 7, 8, 9 };

// 偶数をすべて取得
List<int> results = numbers.FindAll(n => n % 2 == 0);

foreach (var n in results)
{
    Console.WriteLine(n);
}
実行結果

2
8

条件に合う要素がゼロ件だった場合

FindAll()は要素が見つからなくても null は返しません。

空のList(Count = 0)が返るため、nullチェックは不要です。

if (results.Count > 0) で件数チェックするだけでOKです。

おしけん

応用として、部分一致でフィルタリングもできますよ

var names = new List<string> { "田中一郎", "山田花子", "田中二郎", "鈴木太郎" };

// "田中"を含む要素をすべて取得
List<string> results = names.FindAll(s => s.Contains("田中"));

foreach (var name in results)
{
    Console.WriteLine(name);
}
実行結果

田中一郎
田中二郎

おしけん

「1件だけほしい → Find()」「全件ほしい → FindAll()」と使い分ければバッチリです!

FindIndex():インデックスを取得

FindIndex() は、条件に合う最初の要素のインデックス(位置番号)を返します。

要素の値そのものではなく「何番目にあるか」を知りたいときに使います。

var list = new List<int> { 1, 2, 3, 7, 8, 9 };

// 偶数の最初のインデックスを取得
int index = list.FindIndex(n => n % 2 == 0);

Console.WriteLine(index); // 出力:1(2番目の要素)

// 見つからない場合は -1 が返る
int notFound = list.FindIndex(n => n > 100);
Console.WriteLine(notFound); // 出力:-1
実行結果

1
-1

FindIndex() を使う場面

数値型のリストで「0が存在するかどうか」を判定したいとき、Find()では0と未発見を区別できません。

FindIndex()で戻り値が -1 かどうかを確認すれば、確実に判定できます。

FindLast() / FindLastIndex():後ろから検索

FindLast()FindLastIndex() は、リストの末尾から検索します。

重複データがある場合に「最後に見つかった方」を取得したいときに便利です。

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

// 後ろから偶数を検索して最後の1件を返す
int lastEven = numbers.FindLast(n => n % 2 == 0);
Console.WriteLine(lastEven); // 出力:8

// 後ろから偶数を検索してインデックスを返す
int lastEvenIndex = numbers.FindLastIndex(n => n % 2 == 0);
Console.WriteLine(lastEvenIndex); // 出力:4
実行結果

8
4

カスタムクラスのリストを検索する

実務でよく使うのが、カスタムクラスをリストに格納して検索するパターンです。

ユーザー情報や商品データなど、複数のプロパティを持つオブジェクトをFind()で絞り込む方法を見ていきましょう。

// 商品クラスの定義
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Price { get; set; }
}
// リストを作成
var products = new List<Product>
{
    new Product { Id = 1, Name = "りんご", Price = 150 },
    new Product { Id = 2, Name = "バナナ", Price = 100 },
    new Product { Id = 3, Name = "メロン", Price = 800 },
};

// IDで検索(1件)
Product? target = products.Find(p => p.Id == 2);

if (target != null)
{
    Console.WriteLine($"商品名:{target.Name}、価格:{target.Price}円");
}

// 500円以上の商品をすべて取得
List<Product> expensiveList = products.FindAll(p => p.Price >= 500);

foreach (var p in expensiveList)
{
    Console.WriteLine($"{p.Name}:{p.Price}円");
}
実行結果

商品名:バナナ、価格:100円
メロン:800円

カスタムクラスのリスト検索まとめ

ラムダ式の左辺でリストの要素を受け取り(例:p)、右辺でプロパティにアクセスして条件を書きます(例:p.Id == 2)。

参照型なので戻り値は null になる可能性があり、nullチェックを忘れずに。

FirstOrDefault との使い分け

Find()FirstOrDefault() はよく似ていますが、重要な違いがあります。

Find() はList\<T>専用のメソッドで、FirstOrDefault() はLINQの拡張メソッドです。

メソッド種別特徴
Find()List専用List\<T> のメソッド。パフォーマンス若干有利
FirstOrDefault()LINQIEnumerable\<T> の拡張メソッド。List以外でも使用可能
First()LINQ見つからない場合に 例外が発生。必ず存在する確信がある場合のみ使用
var list = new List<int> { 1, 2, 3, 7, 8, 9 };

// Find:List<T> のメソッド
int result1 = list.Find(n => n > 5); // 7

// FirstOrDefault:LINQ の拡張メソッド
int result2 = list.FirstOrDefault(n => n > 5); // 7

// First:見つからないと例外が発生する!
// int result3 = list.First(n => n > 100);  // ← InvalidOperationException!
First() は使う場面を選んで

First() は要素が必ず存在すると確信できる場合のみ使います。

「見つからないかもしれない」という場面では FirstOrDefault() か Find() を使いましょう。

実務では予期しない例外の原因になることが多いです。

悩んでる人

FindとFirstOrDefaultどっちを使えばいいの?

おしけん

対象がListなら Find()、LINQを使った処理と組み合わせたい場合はFirstOrDefault()という感じで覚えておけばOKです!

検索メソッド比較まとめ

これまでに紹介してきた、List検索メソッドをまとめています。

ここで振り返りましょう!!

メソッド戻り値件数見つからない場合使いどころ
Find()T型1件型の既定値(null/0)最初の1件が欲しい
FindAll()List\<T>全件空のList全件まとめて欲しい
FindIndex()int1件-1位置番号を知りたい
FindLast()T型1件型の既定値(null/0)最後の1件が欲しい
FindLastIndex()int1件-1最後の位置番号を知りたい
FirstOrDefault()T型1件型の既定値(null/0)LINQ/IEnumerableで統一
First()T型1件例外が発生!必ず存在する確信がある場合

まとめ

  • Find() は条件に合う最初の1件を返す。見つからない場合は型の既定値(null/0)が返る
  • FindAll() は全件をList\<T>で返す。見つからなくても例外は発生せず空のListが返る
  • FindIndex() はインデックスを返す。見つからない場合は -1 が返るため存在チェックに使いやすい
  • FindLast() / FindLastIndex() は後ろから検索。重複データで最後のものを取りたいときに使う
  • Find() vs FirstOrDefault() は対象がListなら基本的にFind()、LINQ処理と組み合わせるならFirstOrDefault()
  • 参照型リストのFind()結果は必ずnullチェックを忘れずに
  • 数値型リストで「0かどうか」を判定する場合は FindIndex() を使って -1 チェックするのがベター
おしけん

Findメソッドはラムダ式と組み合わせることで、非常にシンプルに検索処理を書けます。まずはFind()とFindAll()の2つをしっかり使えるようになると、コードがグッとスッキリしますよ!

C#のList検索をマスターすると、foreach + if の組み合わせでゴリゴリ書いていたコードをスッキリ1行で表現できます。

次のステップとして、LINQのWhereやSelectにも挑戦してみましょう!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次