Skip to content

第12章 List<T> と LINQ

この章では、複数のデータを柔軟に扱うための List と、データの検索・絞り込み・並び替えを行うための LINQ を学習します。

第6章では、配列を使って複数の値を管理しました。

int[] scores = { 80, 75, 90, 68, 85 };

配列は、複数の値をまとめて扱うために便利です。

しかし、配列には次のような特徴があります。

作成時に要素数が決まる
後から要素を追加しにくい
削除や検索を自分で書く必要がある

一方、List<T> を使うと、後からデータを追加したり、削除したりしやすくなります。

List<int> scores = new List<int>();
scores.Add(80);
scores.Add(75);
scores.Add(90);

さらに、LINQを使うと、複数のデータから条件に合うものを取り出したり、並び替えたりできます。

List<Employee> salesEmployees = employees
.Where(employee => employee.Department == "営業部")
.ToList();

後の章では、Oracle Databaseの employees 表から取得した複数件の社員情報を、List<Employee> として扱います。

この章は、DB連携、Webアプリ、デスクトップアプリにつながる重要な準備です。


この章でできるようになること

Section titled “この章でできるようになること”

この章を終えると、次のことができるようになります。

  • List<T> とは何かを説明できる
  • 配列と List<T> の違いを説明できる
  • List<int>List<string> を作成できる
  • Add を使って要素を追加できる
  • Count を使って要素数を取得できる
  • foreach 文で List<T> の要素を処理できる
  • List<Employee> のように、自作クラスのリストを扱える
  • LINQとは何かをおおまかに説明できる
  • Where を使って条件に合うデータを絞り込める
  • FirstOrDefault を使って条件に合う最初のデータを取得できる
  • OrderByOrderByDescending で並び替えできる
  • Select を使って必要な項目だけを取り出せる
  • SumAverageCount を使って集計できる
  • null の可能性を意識して検索結果を扱える

項目内容
開発環境Visual Studio 2022
プロジェクト種類コンソール アプリ
対象フレームワーク.NET 8
プロジェクト名Chapter12_ListLinq

作業を始める前に、次の内容を確認してください。

  • 配列を使って複数の値を扱える
  • foreach 文を使える
  • クラスを作成できる
  • プロパティを定義できる
  • オブジェクト初期化子を使える
  • null の意味を説明できる
  • Employee? のようなnull許容参照型をおおまかに理解している
  • 第11章の内容をGitに提出済みである

配列は、同じ型の複数の値をまとめて扱う仕組みです。

using System;
class Program
{
static void Main()
{
int[] scores = { 80, 75, 90 };
foreach (int score in scores)
{
Console.WriteLine(score);
}
}
}

実行結果:

80
75
90

配列は便利ですが、作成時に要素数が決まります。

int[] scores = new int[3];

この場合、基本的には3件分の領域として考えます。

後から自由に件数を増やしたい場合は、List<T> の方が扱いやすくなります。


List<T> は、複数のデータを管理するためのコレクションです。

T の部分には、扱いたい型を指定します。

書き方意味
List<int>int 型の値を複数管理する
List<string>string 型の値を複数管理する
List<Employee>Employee 型のオブジェクトを複数管理する

List<T> を使うには、通常、次の using を書きます。

using System.Collections.Generic;

次のコードを入力して実行してください。

using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<int> scores = new List<int>();
scores.Add(80);
scores.Add(75);
scores.Add(90);
foreach (int score in scores)
{
Console.WriteLine(score);
}
}
}

実行結果:

80
75
90

Add メソッドを使うことで、リストに値を追加できます。

scores.Add(80);

List<T> の要素数は、Count プロパティで取得できます。

using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<int> scores = new List<int>();
scores.Add(80);
scores.Add(75);
scores.Add(90);
Console.WriteLine($"件数:{scores.Count}");
}
}

実行結果:

件数:3

配列では要素数を Length で取得しました。

scoresArray.Length

List<T> では Count を使います。

scores.Count

どちらもプロパティなので、通常 () は付けません。


List<T> は、最初から値を入れて作ることもできます。

using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> departments = new List<string>
{
"総務",
"営業",
"開発",
"マーケティング"
};
foreach (string department in departments)
{
Console.WriteLine(department);
}
}
}

実行結果:

総務
営業
開発
マーケティング

List<T> も配列と同じように、インデックスで要素にアクセスできます。

using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> departments = new List<string>
{
"総務",
"営業",
"開発"
};
Console.WriteLine(departments[0]);
Console.WriteLine(departments[1]);
Console.WriteLine(departments[2]);
}
}

実行結果:

総務
営業
開発

配列と同じように、インデックスは0から始まります。


Remove メソッドを使うと、指定した値を削除できます。

using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> departments = new List<string>
{
"総務",
"営業",
"開発"
};
departments.Remove("営業");
foreach (string department in departments)
{
Console.WriteLine(department);
}
}
}

実行結果:

総務
開発

Remove は、指定した値が見つかった場合に削除します。


項目配列List
要素数基本的に固定追加・削除しやすい
要素数の取得LengthCount
要素の追加やや面倒Add
要素の削除やや面倒RemoveRemoveAt
向いている場面件数が決まっているデータ件数が変わるデータ

後のDB接続では、SELECT文の結果が何件になるか実行してみないと分からないことがあります。

そのため、DBから取得した複数件のデータは、配列よりも List<T> で扱う方が自然です。


List<T>T には、自分で作ったクラスも指定できます。

ここでは、Employee クラスのリストを作成します。

using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<Employee> employees = new List<Employee>();
employees.Add(new Employee
{
EmployeeId = 1001,
EmployeeName = "山田太郎",
DepartmentName = "総務"
});
employees.Add(new Employee
{
EmployeeId = 1002,
EmployeeName = "佐藤花子",
DepartmentName = "営業"
});
employees.Add(new Employee
{
EmployeeId = 1003,
EmployeeName = "鈴木一郎",
DepartmentName = "開発"
});
foreach (Employee employee in employees)
{
Console.WriteLine($"{employee.EmployeeId}{employee.EmployeeName}{employee.DepartmentName}");
}
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
}

実行結果:

1001:山田太郎(総務)
1002:佐藤花子(営業)
1003:鈴木一郎(開発)

Employeeオブジェクトを複数管理する

Section titled “Employeeオブジェクトを複数管理する”

List<Employee> は、複数の社員オブジェクトをまとめて管理します。

employees
├─ Employee 1001 山田太郎
├─ Employee 1002 佐藤花子
└─ Employee 1003 鈴木一郎

後のDB接続編では、Oracle Databaseの employees 表から取得した1行ずつを Employee オブジェクトに変換し、List<Employee> に追加します。

employees表
↓ SELECT
OracleDataReader
↓ 1行ずつ読み取る
Employeeオブジェクト
↓ Add
List<Employee>

この章では、まず手作業で List<Employee> を作成し、複数の社員データを扱う練習をします。


メソッドでサンプルデータを作る

Section titled “メソッドでサンプルデータを作る”

毎回 Main メソッドの中にサンプルデータを書くと長くなるため、サンプルデータ作成用のメソッドを用意します。

using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
foreach (Employee employee in employees)
{
Console.WriteLine($"{employee.EmployeeId}{employee.EmployeeName}{employee.DepartmentName}");
}
}
static List<Employee> CreateSampleEmployees()
{
List<Employee> employees = new List<Employee>
{
new Employee
{
EmployeeId = 1001,
EmployeeName = "山田太郎",
DepartmentName = "総務",
Salary = 500000
},
new Employee
{
EmployeeId = 1002,
EmployeeName = "佐藤花子",
DepartmentName = "営業",
Salary = 420000
},
new Employee
{
EmployeeId = 1003,
EmployeeName = "鈴木一郎",
DepartmentName = "開発",
Salary = 380000
}
};
return employees;
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

まずは、LINQを使わずに for 文で検索してみます。

using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
Employee? foundEmployee = null;
foreach (Employee employee in employees)
{
if (employee.EmployeeId == 1002)
{
foundEmployee = employee;
break;
}
}
if (foundEmployee == null)
{
Console.WriteLine("社員が見つかりませんでした。");
}
else
{
Console.WriteLine($"{foundEmployee.EmployeeId}{foundEmployee.EmployeeName}");
}
}
static List<Employee> CreateSampleEmployees()
{
return new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎", DepartmentName = "総務", Salary = 500000 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子", DepartmentName = "営業", Salary = 420000 },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎", DepartmentName = "開発", Salary = 380000 }
};
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

実行結果:

1002:佐藤花子

このように、List<Employee> に対して繰り返し処理を行うことで、条件に合うデータを探せます。

ただし、検索や絞り込みを書くたびに foreachif を書くのは少し面倒です。

そこで、LINQを使います。


LINQは、コレクションのデータを検索、絞り込み、並び替え、変換するための機能です。

LINQは、次のようなデータに対して使えます。

配列
List<T>
DBから取得したデータを入れたList<T>

この章では、主に List<Employee> に対してLINQを使います。

LINQを使うには、通常、次の using を書きます。

using System.Linq;

.NET 8のプロジェクトでは自動的に使える場合もありますが、研修では必要に応じて明示的に書いておきます。


Where を使うと、条件に合うデータだけを取り出せます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
List<Employee> salesEmployees = employees
.Where(employee => employee.DepartmentName == "営業")
.ToList();
foreach (Employee employee in salesEmployees)
{
Console.WriteLine($"{employee.EmployeeId}{employee.EmployeeName}{employee.DepartmentName}");
}
}
static List<Employee> CreateSampleEmployees()
{
return new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎", DepartmentName = "総務", Salary = 500000 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子", DepartmentName = "営業", Salary = 420000 },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎", DepartmentName = "開発", Salary = 380000 },
new Employee { EmployeeId = 1004, EmployeeName = "田中次郎", DepartmentName = "営業", Salary = 350000 }
};
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

実行結果:

1002:佐藤花子(営業)
1004:田中次郎(営業)

次の部分に注目してください。

employee => employee.DepartmentName == "営業"

これは ラムダ式 と呼ばれる書き方です。

この章では、まず次のように読んでください。

employee を1件ずつ取り出し、
employee.DepartmentName が "営業" のものだけを選ぶ

Where の中では、リストの要素が1件ずつ employee に入ります。

1件目のEmployee
2件目のEmployee
3件目のEmployee
...

その1件が条件に合うかどうかを、=> の右側で判定しています。


Where の結果を List<Employee> として受け取りたい場合は、最後に ToList() を付けます。

List<Employee> salesEmployees = employees
.Where(employee => employee.DepartmentName == "営業")
.ToList();

この章では、まず次のように覚えてください。

Whereで絞り込む
ToListでList<T>にする

条件に合う最初の1件を取得したい場合は、FirstOrDefault を使います。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
Employee? employee = employees
.FirstOrDefault(employee => employee.EmployeeId == 1002);
if (employee == null)
{
Console.WriteLine("社員が見つかりませんでした。");
}
else
{
Console.WriteLine($"{employee.EmployeeId}{employee.EmployeeName}");
}
}
static List<Employee> CreateSampleEmployees()
{
return new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎", DepartmentName = "総務", Salary = 500000 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子", DepartmentName = "営業", Salary = 420000 },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎", DepartmentName = "開発", Salary = 380000 }
};
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

実行結果:

1002:佐藤花子

該当するデータが見つからなかった場合、FirstOrDefaultnull を返すことがあります。

そのため、戻り値を Employee? として受け取り、null チェックを行います。


LINQの Count() を使うと、条件に合う件数を数えられます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
int salesCount = employees
.Count(employee => employee.DepartmentName == "営業");
Console.WriteLine($"営業部の人数:{salesCount}");
}
static List<Employee> CreateSampleEmployees()
{
return new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎", DepartmentName = "総務", Salary = 500000 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子", DepartmentName = "営業", Salary = 420000 },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎", DepartmentName = "開発", Salary = 380000 },
new Employee { EmployeeId = 1004, EmployeeName = "田中次郎", DepartmentName = "営業", Salary = 350000 }
};
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

実行結果:

営業部の人数:2人

ここで注意したいのは、Count には2種類の使い方があることです。

書き方種類意味
employees.Countプロパティリスト全体の件数
employees.Count(...)LINQメソッド条件に合う件数

() が付くかどうかにも注目してください。


12-4 LINQで検索・絞り込みを行う

Section titled “12-4 LINQで検索・絞り込みを行う”

社員名に特定の文字が含まれるデータを検索します。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
Console.WriteLine("検索する名前を入力してください。");
string keyword = Console.ReadLine() ?? "";
List<Employee> results = employees
.Where(employee => employee.EmployeeName.Contains(keyword))
.ToList();
foreach (Employee employee in results)
{
Console.WriteLine($"{employee.EmployeeId}{employee.EmployeeName}{employee.DepartmentName}");
}
}
static List<Employee> CreateSampleEmployees()
{
return new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎", DepartmentName = "総務", Salary = 500000 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子", DepartmentName = "営業", Salary = 420000 },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎", DepartmentName = "開発", Salary = 380000 },
new Employee { EmployeeId = 1004, EmployeeName = "田中次郎", DepartmentName = "営業", Salary = 350000 }
};
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

実行例:

検索する名前を入力してください。
1001:山田太郎(総務)
1004:田中次郎(営業)

Contains を使うことで、名前の一部にキーワードが含まれているかを判定しています。


条件を複数組み合わせることもできます。

次の例では、部署が営業で、給与が400000円以上の社員を取り出します。

List<Employee> results = employees
.Where(employee => employee.DepartmentName == "営業" && employee.Salary >= 400000)
.ToList();

全体のコードは次の通りです。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
List<Employee> results = employees
.Where(employee => employee.DepartmentName == "営業" && employee.Salary >= 400000)
.ToList();
foreach (Employee employee in results)
{
Console.WriteLine($"{employee.EmployeeName}{employee.DepartmentName}{employee.Salary}");
}
}
static List<Employee> CreateSampleEmployees()
{
return new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎", DepartmentName = "総務", Salary = 500000 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子", DepartmentName = "営業", Salary = 420000 },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎", DepartmentName = "開発", Salary = 380000 },
new Employee { EmployeeId = 1004, EmployeeName = "田中次郎", DepartmentName = "営業", Salary = 350000 }
};
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

実行結果:

佐藤花子:営業:420000円

検索結果が0件の場合もあります。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
List<Employee> results = employees
.Where(employee => employee.DepartmentName == "人事")
.ToList();
if (results.Count == 0)
{
Console.WriteLine("該当する社員は見つかりませんでした。");
}
else
{
foreach (Employee employee in results)
{
Console.WriteLine(employee.EmployeeName);
}
}
}
static List<Employee> CreateSampleEmployees()
{
return new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎", DepartmentName = "総務", Salary = 500000 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子", DepartmentName = "営業", Salary = 420000 },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎", DepartmentName = "開発", Salary = 380000 }
};
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

実行結果:

該当する社員は見つかりませんでした。

Webアプリやデスクトップアプリでも、検索結果が0件の場合の表示は重要です。


12-5 LINQで並び替え・集計を行う

Section titled “12-5 LINQで並び替え・集計を行う”

OrderBy を使うと、指定した項目で昇順に並び替えできます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
List<Employee> sortedEmployees = employees
.OrderBy(employee => employee.Salary)
.ToList();
foreach (Employee employee in sortedEmployees)
{
Console.WriteLine($"{employee.EmployeeName}{employee.Salary}");
}
}
static List<Employee> CreateSampleEmployees()
{
return new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎", DepartmentName = "総務", Salary = 500000 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子", DepartmentName = "営業", Salary = 420000 },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎", DepartmentName = "開発", Salary = 380000 }
};
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

実行結果:

鈴木一郎:380000円
佐藤花子:420000円
山田太郎:500000円

OrderByDescendingで降順に並び替える

Section titled “OrderByDescendingで降順に並び替える”

降順に並び替えたい場合は、OrderByDescending を使います。

List<Employee> sortedEmployees = employees
.OrderByDescending(employee => employee.Salary)
.ToList();

給与が高い順に表示したい場合などに使えます。


Sum を使うと、指定した数値の合計を求められます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
int totalSalary = employees.Sum(employee => employee.Salary);
Console.WriteLine($"給与合計:{totalSalary}");
}
static List<Employee> CreateSampleEmployees()
{
return new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎", DepartmentName = "総務", Salary = 500000 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子", DepartmentName = "営業", Salary = 420000 },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎", DepartmentName = "開発", Salary = 380000 }
};
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

実行結果:

給与合計:1300000円

Average を使うと、平均を求められます。

double averageSalary = employees.Average(employee => employee.Salary);
Console.WriteLine($"平均給与:{averageSalary}");

表示用に丸めたい場合は、Math.Round と組み合わせてもよいです。

double roundedAverage = Math.Round(averageSalary, 1);

Selectで必要な項目だけを取り出す

Section titled “Selectで必要な項目だけを取り出す”

Select を使うと、リストの各要素から必要な情報だけを取り出せます。

次の例では、社員名だけを取り出します。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
List<Employee> employees = CreateSampleEmployees();
List<string> employeeNames = employees
.Select(employee => employee.EmployeeName)
.ToList();
foreach (string name in employeeNames)
{
Console.WriteLine(name);
}
}
static List<Employee> CreateSampleEmployees()
{
return new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田太郎", DepartmentName = "総務", Salary = 500000 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤花子", DepartmentName = "営業", Salary = 420000 },
new Employee { EmployeeId = 1003, EmployeeName = "鈴木一郎", DepartmentName = "開発", Salary = 380000 }
};
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public string DepartmentName { get; set; } = "";
public int Salary { get; set; }
}

実行結果:

山田太郎
佐藤花子
鈴木一郎

Select では、必要な項目だけを持つ新しい形のデータを作ることもできます。

var displayEmployees = employees
.Select(employee => new
{
employee.EmployeeId,
employee.EmployeeName
})
.ToList();

この new { ... } は匿名型と呼ばれます。

この章では深く扱いませんが、画面表示用に必要な項目だけを取り出す考え方は、後のWebアプリやデスクトップアプリでも重要です。


12-6 DB連携に向けたListの考え方

Section titled “12-6 DB連携に向けたListの考え方”

DBの1行を1つのオブジェクトとして扱う

Section titled “DBの1行を1つのオブジェクトとして扱う”

後の章では、Oracle Databaseの employees 表からデータを取得します。

イメージは次の通りです。

employees表
employee_id | employee_name | department_id
------------|---------------|--------------
1001 | 山田二郎 | 1
1002 | 佐藤昭夫 | 2
1003 | 山口洋子 | 3

C#側では、1行分を Employee オブジェクトとして扱います。

class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; } = "";
public int DepartmentId { get; set; }
}

複数行の結果は、List<Employee> として扱います。

List<Employee> employees = new List<Employee>();

DBから取得した後の処理を想定する

Section titled “DBから取得した後の処理を想定する”

この章では、まだDBには接続しません。

しかし、次のように手作業で作成した List<Employee> は、DBから取得した結果と同じように扱えます。

List<Employee> employees = new List<Employee>
{
new Employee { EmployeeId = 1001, EmployeeName = "山田二郎", DepartmentId = 1 },
new Employee { EmployeeId = 1002, EmployeeName = "佐藤昭夫", DepartmentId = 2 },
new Employee { EmployeeId = 1003, EmployeeName = "山口洋子", DepartmentId = 3 }
};

このリストに対して、LINQで検索できます。

Employee? employee = employees
.FirstOrDefault(employee => employee.EmployeeId == 1002);

部署で絞り込むこともできます。

List<Employee> departmentEmployees = employees
.Where(employee => employee.DepartmentId == 1)
.ToList();

つまり、DB接続編に入る前に、List<Employee> と LINQ に慣れておくことが重要です。


Webアプリ・デスクトップアプリでの利用イメージ

Section titled “Webアプリ・デスクトップアプリでの利用イメージ”

Webアプリでは、ControllerからViewへ List<Employee> を渡すことがあります。

Controller
List<Employee>
Viewで一覧表示

デスクトップアプリでは、List<Employee> をDataGridViewに表示することがあります。

Oracle DB
List<Employee>
DataGridView

この章で学ぶ内容は、後半のアプリ作成にそのままつながります。


この章でよくあるつまずきを確認します。

つまずき原因対応
List<T>T が分からないジェネリック型に慣れていないT には扱う型を書くと考える
List<int>List<Employee> の違いが分からない値のリストとオブジェクトのリストを混同している何を複数管理したいかで型を決める
Add を忘れるリストに要素を追加していないlist.Add(...) を確認する
Count()Count を混同するプロパティとLINQメソッドが混ざっている全件数は Count、条件付き件数は Count(...) と考える
Where の結果をそのまま List<T> に代入できないToList() を忘れているWhere(...).ToList() と書く
ラムダ式が読めない=> の意味に慣れていない「1件ずつ取り出して条件を見る」と読む
FirstOrDefault の結果でエラーになる見つからず null なのにプロパティを使っているnull チェックを行う
Contains の検索結果が想定と違う大文字小文字や空白の違い必要に応じて TrimToLower を使う
LINQを使いすぎて読みにくい1行に詰め込みすぎている改行して読みやすく書く

次の項目について、自分で説明できるか確認してください。

  • List<T> とは何かを説明できる
  • 配列と List<T> の違いを説明できる
  • List<int> を作成できる
  • List<string> を作成できる
  • List<Employee> を作成できる
  • Add を使ってリストに要素を追加できる
  • Count でリストの件数を取得できる
  • foreach でリストの要素を順番に処理できる
  • LINQとは何かをおおまかに説明できる
  • Where を使って絞り込みができる
  • FirstOrDefault を使って1件取得できる
  • FirstOrDefault の結果が null になる可能性を説明できる
  • OrderBy で並び替えできる
  • SumAverage で集計できる
  • Select で必要な項目だけを取り出せる
  • DBから取得した複数件のデータを List<Employee> として扱うイメージを説明できる

研修の進め方によっては、隣の人またはチーム内で説明確認を行います。

次の内容を、自分の言葉で説明してください。

  1. 配列と List<T> の違いは何ですか。
  2. List<Employee> は何を表していますか。
  3. employees.Countemployees.Count(...) の違いは何ですか。
  4. Where はどのようなときに使いますか。
  5. FirstOrDefault の結果を使う前に注意することは何ですか。
  6. DBから取得した複数件の社員データを、C#ではどのように扱う予定ですか。

説明するときは、完全な答えでなくても構いません。
自分の言葉で説明しようとすることが大切です。


この章の演習課題に取り組みます。

制限時間は 75分 です。

時間内にすべて完成しなくても構いません。
できたところまでを保存し、Gitに提出してください。


まずは、全員が必須課題に取り組んでください。


List<int> を使って、次の点数を管理し、すべて表示してください。

80, 75, 90, 68, 85

実行結果例:

80
75
90
68
85

条件:

  • List<int> を使う
  • Add で点数を追加する
  • foreach で表示する

課題12-2 Listで部署一覧を管理する

Section titled “課題12-2 Listで部署一覧を管理する”

List<string> を使って、次の部署名を管理し、件数と一覧を表示してください。

総務, 営業, 開発, マーケティング

実行結果例:

部署数:4
総務
営業
開発
マーケティング

条件:

  • List<string> を使う
  • Count を使う
  • foreach を使う

Employee クラスを作成し、List<Employee> で3人分の社員情報を管理してください。

プロパティ:

プロパティ名
EmployeeIdint
EmployeeNamestring
DepartmentNamestring

実行結果例:

1001:山田太郎(総務)
1002:佐藤花子(営業)
1003:鈴木一郎(開発)

条件:

  • Employee クラスを作成する
  • List<Employee> を使う
  • オブジェクト初期化子を使う
  • foreach で表示する

課題12-3の List<Employee> を使い、部署名が "営業" の社員だけを表示してください。

実行結果例:

1002:佐藤花子(営業)

条件:

  • using System.Linq; を書く
  • Where を使う
  • ToList() を使う

課題12-5 FirstOrDefaultで社員ID検索する

Section titled “課題12-5 FirstOrDefaultで社員ID検索する”

社員IDを指定し、該当する社員を1件取得してください。

実行結果例:

1002:佐藤花子

該当しない場合の実行結果例:

社員が見つかりませんでした。

条件:

  • FirstOrDefault を使う
  • 結果を Employee? で受け取る
  • null チェックを行う

必須課題が終わった人は、発展課題に取り組んでください。


課題12-6 社員名の部分一致検索

Section titled “課題12-6 社員名の部分一致検索”

社員名に入力されたキーワードが含まれる社員だけを表示してください。

実行例:

検索キーワードを入力してください。
1001:山田太郎(総務)
1004:田中次郎(営業)

条件:

  • Console.ReadLine を使う
  • Contains を使う
  • Where を使う
  • 検索結果が0件の場合はメッセージを表示する

課題12-7 給与の高い順に表示する

Section titled “課題12-7 給与の高い順に表示する”

Employee クラスに Salary プロパティを追加し、給与の高い順に社員を表示してください。

実行結果例:

山田太郎:500000円
佐藤花子:420000円
鈴木一郎:380000円

条件:

  • Salary プロパティを追加する
  • OrderByDescending を使う
  • ToList() を使う

課題12-8 給与合計と平均を求める

Section titled “課題12-8 給与合計と平均を求める”

List<Employee> から給与合計と平均給与を求めて表示してください。

実行結果例:

給与合計:1300000円
平均給与:433333.3333333333円

条件:

  • Sum を使う
  • Average を使う
  • 必要に応じて Math.Round を使ってもよい

課題12-9 部署と給与で複数条件検索する

Section titled “課題12-9 部署と給与で複数条件検索する”

部署が "営業" で、給与が 400000 円以上の社員だけを表示してください。

実行結果例:

佐藤花子:営業:420000円

条件:

  • Where を使う
  • && を使って複数条件を指定する

課題12-10 社員名だけを取り出す

Section titled “課題12-10 社員名だけを取り出す”

Select を使って、社員名だけの List<string> を作成し、表示してください。

実行結果例:

山田太郎
佐藤花子
鈴木一郎

条件:

  • Select を使う
  • List<string> として受け取る
  • foreach で表示する

課題12-11 DBデータを想定したEmployeeリストを作る

Section titled “課題12-11 DBデータを想定したEmployeeリストを作る”

後のDB接続編を想定し、次のプロパティを持つ Employee クラスを作成してください。

プロパティ名
EmployeeIdint
EmployeeNamestring
Yomistring?
ManagerIdint?
HireDateDateTime
Salarydecimal?
Commissiondecimal?
DepartmentIdint

3件分のサンプルデータを List<Employee> に入れ、次のように表示してください。

実行結果例:

1001:山田二郎:部署ID 1:給与 500000
1020:内田雄介:部署ID 1:給与 200000
1021:高田明:部署ID 1:給与 200000

条件:

  • List<Employee> を使う
  • string?int?decimal? を使う
  • 給与が null の場合は "未設定" と表示する
  • 後のOracle DB接続編の準備として考える

課題が終わったら、できたところまでをGitに提出します。

まず、現在の状態を確認します。

Terminal window
git status

変更されたファイルを追加します。

Terminal window
git add .

コミットします。

Terminal window
git commit -m "Chapter12 ListとLINQ"

ファイルサーバー上のリポジトリへpushします。

Terminal window
git push

Gitの操作でエラーが出た場合は、自己判断で同じ操作を繰り返さず、講師に確認してください。


提出前に、次の項目を確認してください。

  • List<int> を使えている
  • List<string> を使えている
  • List<Employee> を使えている
  • Add で要素を追加できている
  • Count で件数を取得できている
  • foreach でリストを処理できている
  • Where で絞り込みができている
  • FirstOrDefault で1件取得できている
  • FirstOrDefault の結果を null チェックしている
  • OrderBy または OrderByDescending を使えている
  • Sum または Average を使えている
  • Select を使えている
  • インデントが整っている
  • Gitにcommitしている
  • Gitにpushしている

この章では、List<T> と LINQ について学習しました。

この章で学んだ主な内容は次の通りです。

  • List<T> は、同じ型のデータを複数管理するためのコレクションである
  • T には、intstringEmployee などの型を指定する
  • List<T> は、配列よりも要素の追加や削除がしやすい
  • Add を使うと、リストに要素を追加できる
  • Count を使うと、リストの件数を取得できる
  • foreach を使うと、リストの要素を順番に処理できる
  • List<Employee> を使うと、複数の社員オブジェクトをまとめて扱える
  • LINQを使うと、検索、絞り込み、並び替え、集計ができる
  • Where は、条件に合うデータを絞り込む
  • FirstOrDefault は、条件に合う最初の1件を取得する
  • FirstOrDefault の結果は null になる可能性がある
  • OrderByOrderByDescending で並び替えできる
  • SumAverage で集計できる
  • Select で必要な項目だけを取り出せる
  • 後のDB接続編では、DBから取得した複数件のデータを List<Employee> として扱う

次章では、継承とポリモーフィズム を学習します。

クラス同士の共通点をまとめたり、同じ呼び出し方で異なる動きをさせたりする考え方を学びます。
現場の既存コードを読むうえでも重要な考え方です。