C#のListから生徒を検索しよう!foreach・Find・FindAllを初心者向けに解説

広告

前回の記事「C#のListから要素を削除しよう!Remove・RemoveAt・Clearを初心者向けに解説」では、Listから生徒を削除する方法を確認しました。

生徒を追加・削除できるようになると、次は「登録した生徒の中から、目的の人を探したい」という場面が出てきます。

人数が3人なら目で探せますが、30人、100人と増えると大変です。そこで今回は、Listから条件に合う生徒を検索してみましょう。

最初はforeach文とif文を組み合わせ、検索の仕組みを確認します。その後、FindFindAllを使って、同じ処理を短く書き換えます。

Listを検索する3つの方法

この記事で扱う3つの方法には、次の違いがあります。

C#のListをforeachとif、Find、FindAllで検索する方法の比較図
foreach + ifで仕組みを確認し、Findで最初の1件、FindAllで条件に合う全員を取得します。
  • foreach + if:1人ずつ取り出して条件を確認する
  • Find:条件に合う最初の1件を取得する
  • FindAll:条件に合うすべての要素を新しいListで取得する

まずは処理の流れが見えやすいforeach + ifから始めます。

今回使うStudentリスト

今回は、4人の生徒をListに入れておきます。

List<Student> students = new List<Student>();

students.Add(new Student { Name = "田中", Score = 75 });
students.Add(new Student { Name = "佐藤", Score = 82 });
students.Add(new Student { Name = "鈴木", Score = 88 });
students.Add(new Student { Name = "高橋", Score = 65 });

このListから、名前が「鈴木」の生徒や、点数が80点以上の生徒を探します。

foreach文とif文で名前を検索する

foreach文で生徒を1人ずつ取り出し、if文で名前を確認します。

foreach (var student in students)
{
    if (student.Name == "鈴木")
    {
        Console.WriteLine($"{student.Name}さんを見つけました。");
        student.ShowScore();
    }
}

student.Name == "鈴木"は、「今取り出した生徒の名前が鈴木と同じか」を確認しています。

田中さんと佐藤さんでは条件がfalseになります。鈴木さんを取り出したときだけ条件がtrueになり、メッセージと点数が表示されます。

見つけたらbreakで検索を終える

探している生徒が1人だけなら、見つけた後に残りの生徒を確認する必要はありません。breakを使うと、foreach文を途中で終了できます。

foreach (var student in students)
{
    if (student.Name == "鈴木")
    {
        student.ShowScore();
        break;
    }
}

breakが実行されると、それ以降の高橋さんは確認せずに繰り返しを終えます。

見つからなかった場合も表示する

検索結果が見つかったかどうかを覚えておくには、bool変数を使います。

bool found = false;

foreach (var student in students)
{
    if (student.Name == "鈴木")
    {
        student.ShowScore();
        found = true;
        break;
    }
}

if (found == false)
{
    Console.WriteLine("生徒が見つかりませんでした。");
}

最初はfalseにしておき、見つかったときにtrueへ変更します。最後までfalseのままなら、条件に合う生徒はいなかったことが分かります。

Findで最初の1件を取得する

foreach文とif文で書いた検索は、Findを使うと1行で表せます。

Student foundStudent = students.Find(student => student.Name == "鈴木");

Findは、Listの先頭から順番に条件を確認し、最初に条件へ合った要素を返します。

if (foundStudent != null)
{
    foundStudent.ShowScore();
}
else
{
    Console.WriteLine("生徒が見つかりませんでした。");
}

名前が鈴木の生徒が見つかれば、そのStudentfoundStudentに入ります。見つからなければnullになります。

ラムダ式の読み方

Findの中に書いた次の部分を、ラムダ式と呼びます。

student => student.Name == "鈴木"

今は、次のように読むとよいでしょう。

  • student:Listから取り出した1人の生徒
  • =>:その生徒について、右側の条件を確認する
  • student.Name == "鈴木":名前が鈴木と同じか

つまり、「生徒を1人ずつ確認して、名前が鈴木の生徒を探す」という意味です。最初からラムダ式を暗記する必要はありません。foreach文とif文を短く表した形だと考えてみてください。

Findで点数を条件に検索する

名前だけでなく、点数を条件にすることもできます。

Student foundStudent = students.Find(student => student.Score >= 80);

このListで最初に80点以上なのは、82点の佐藤さんです。そのため、foundStudentには佐藤さんが入ります。

88点の鈴木さんも条件には合っていますが、Findが返すのは最初の1件だけです。

FindAllで条件に合う全員を取得する

80点以上の生徒を全員取り出したい場合は、FindAllを使います。

List<Student> highScoreStudents =
    students.FindAll(student => student.Score >= 80);

FindAllの検索結果は1人とは限らないため、戻り値もList<Student>です。

foreach (var student in highScoreStudents)
{
    student.ShowScore();
}

実行すると、82点の佐藤さんと88点の鈴木さんが表示されます。75点の田中さんと65点の高橋さんは含まれません。

FindAllの結果が0件の場合

FindAllで条件に合う生徒がいない場合、nullではなく空のListが返されます。

List<Student> highScoreStudents =
    students.FindAll(student => student.Score >= 100);

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

Countを確認すると、検索結果が何件あったか分かります。

Containsを使うときの注意

Containsは、指定した要素がListに含まれているかをtrueまたはfalseで返します。

Student student = students[0];

bool exists = students.Contains(student);  // true

ただし、今回のようなStudentクラスでは、名前と点数が同じ別のインスタンスを作っても、同じ要素とは判断されません。

Student anotherStudent = new Student
{
    Name = "田中",
    Score = 75
};

bool exists = students.Contains(anotherStudent);  // false

名前などの内容を条件に探したいときは、FindFindAllを使う方が分かりやすいでしょう。

完成コード

using System;
using System.Collections.Generic;

namespace StudentListSearchTutorial
{
    internal class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>();

            students.Add(new Student { Name = "田中", Score = 75 });
            students.Add(new Student { Name = "佐藤", Score = 82 });
            students.Add(new Student { Name = "鈴木", Score = 88 });
            students.Add(new Student { Name = "高橋", Score = 65 });

            Console.Write("検索する生徒の名前を入力してください:");
            string searchName = Console.ReadLine();

            Student foundStudent =
                students.Find(student => student.Name == searchName);

            if (foundStudent != null)
            {
                Console.WriteLine("生徒が見つかりました。");
                foundStudent.ShowScore();
            }
            else
            {
                Console.WriteLine("生徒が見つかりませんでした。");
            }

            Console.WriteLine();
            Console.WriteLine("80点以上の生徒を表示します。");

            List<Student> highScoreStudents =
                students.FindAll(student => student.Score >= 80);

            foreach (var student in highScoreStudents)
            {
                student.ShowScore();
            }
        }
    }

    class Student
    {
        public string Name;
        public int Score;

        public void ShowScore()
        {
            Console.WriteLine($"{Name}さんの点数は{Score}点です。");
        }
    }
}

Visual Studioの設定によっては、Console.ReadLine()Findの戻り値、Nameに関する警告が表示されることがあります。まずは検索条件と結果の流れに注目して、動きを確認してみましょう。

3つの方法の使い分け

  • 検索の仕組みを確認したい:foreach + if
  • 条件に合う最初の1件がほしい:Find
  • 条件に合う全件がほしい:FindAll
  • 同じ要素が含まれているかだけ知りたい:Contains

初心者のうちは、まずforeach + ifで検索できることを確認し、その後でFindFindAllへ書き換えると理解しやすくなります。

今回のまとめ

  • foreach文とif文で、Listを1件ずつ検索できる
  • breakで、見つかった後の繰り返しを終了できる
  • Findで、条件に合う最初の1件を取得できる
  • Findで見つからなかった場合はnullになる
  • FindAllで、条件に合う全件を新しいListとして取得できる
  • FindAllの結果が0件なら、空のListが返る
  • ラムダ式は、1件ずつ条件を確認する処理を短く表している
  • Studentの内容を条件に探す場合は、ContainsよりFindが分かりやすい

1件だけ探すならFind、条件に合う全員を探すならFindAllを使います。

まずは名前で1人を検索し、次に点数を条件として複数の生徒を取り出してみてください。

Listの基本を使って小さな作品を作りたい方は、次の記事でRandomとListを組み合わせたおみくじ作りに挑戦してみましょう。「C#でおみくじを作ろう!RandomとListを使った初心者向けミニ制作」へ進むと、ランダムな番号でListから結果を取り出す流れを学べます。

訪問数 9 回, 今日の訪問数 9回

広告