10日目のテーマとゴール
10日目は「複数の診断結果(Result オブジェクト)をまとめて扱い、集計や検索ができるようにする」ことがテーマです。
昨日は Result クラスを作り、ログ1行を Result に変換できるようになりました。
今日はその Result を まとめて扱う“コレクション” と、
それを効率よく操作するための LINQ(リンク) の入り口を学びます。
ここを越えると、C# のコードが一気に“プロっぽく”なり、
「データを扱うアプリ」を作る力が大きく伸びます。
コレクションとは何か
配列より柔軟な「List<T>」
昨日は Result[](配列)で複数の結果を扱えると説明しました。
しかし配列には弱点があります。
- 要素数を後から増やせない
- 途中で削除しにくい
- データ数が変わるアプリに向かない
そこで登場するのが List<T> です。
List<Result> results = new List<Result>();
C#T の部分に型を入れることで、
「Result 型のデータをいくつでも入れられる箱」になります。
List の基本操作
List は配列より直感的に扱えます。
results.Add(result); // 追加
results.Count // 要素数
results[0] // 0番目の要素
C#List は「増える・減る」が自然にできるため、
ログのように件数が変わるデータに最適です。
ログファイルを「List<Result>」として読み込む
1行ずつ Result に変換して List に入れる
昨日作った ParseLogLine を使って、ログ全体を読み込みます。
static List<Result> LoadResults(string fileName)
{
List<Result> list = new List<Result>();
if (!File.Exists(fileName))
{
return list;
}
string[] lines = File.ReadAllLines(fileName);
for (int i = 0; i < lines.Length; i++)
{
Result r = ParseLogLine(lines[i]);
if (r != null)
{
list.Add(r);
}
}
return list;
}
C#ここでの重要ポイントは次です。
- List は空で始めて、必要なだけ Add していく
- ParseLogLine が null を返したらスキップ
- 最後に List を返す
これで、ログファイル全体が「Result のリスト」として扱えるようになります。
LINQ の入り口:データを“宣言的”に扱う
LINQ とは何か
LINQ(Language Integrated Query)は、
「データを検索・集計・並べ替えするための C# の仕組み」です。
例えば、次のようなことが簡単に書けます。
- 最近5件だけ取り出す
- INDOOR タイプだけ抽出する
- 平均 yesCount を求める
- 日付順に並べ替える
これらを for 文で書くと長くなりますが、
LINQ を使うと短く、読みやすく書けます。
using System.Linq; を追加する
LINQ を使うには、ファイルの先頭に次を追加します。
using System.Linq;
C#LINQ を使った基本操作
1. 最新5件を取り出す
ログが増えてくると、全部表示するのは大変です。
最新5件だけ見たいときはこう書けます。
var latest5 = results
.OrderByDescending(r => r.Timestamp)
.Take(5);
C#ここでのポイントは次です。
- OrderByDescending → 日付の新しい順に並べる
- Take(5) → 上から5件だけ取る
2. INDOOR タイプだけ抽出する
var indoors = results
.Where(r => r.TypeCode == "INDOOR");
C#Where は「条件に合うものだけ取り出す」操作です。
3. 平均 yesCount を求める
double avg = results.Average(r => r.YesCount);
C#Average は「平均値」を求める LINQ の関数です。
4. 最も yesCount が多い結果
var maxResult = results
.OrderByDescending(r => r.YesCount)
.FirstOrDefault();
C#FirstOrDefault は「最初の1件」を返します。
結果がない場合は null になります。
LINQ を使った履歴表示の強化
最新5件だけ表示する ShowRecentHistory
static void ShowRecentHistory(List<Result> results)
{
var latest = results
.OrderByDescending(r => r.Timestamp)
.Take(5);
Console.WriteLine("=== 最近5件の履歴 ===");
foreach (var r in latest)
{
Console.WriteLine(
r.Timestamp.ToString("yyyy-MM-dd HH:mm")
+ " "
+ r.YesCount + "/" + r.Total
+ " "
+ r.GetTypeLabel()
);
}
Console.WriteLine();
}
C#ここでのポイントは次です。
- List<Result> を受け取って LINQ で加工
- foreach で順番に表示
- Result のメソッド(GetTypeLabel)を活用
LINQ を使うと、「データをどう扱いたいか」がコードにそのまま表現されます。
LINQ を使った集計の例
タイプごとの件数を数える
var groups = results
.GroupBy(r => r.TypeCode);
foreach (var g in groups)
{
Console.WriteLine(g.Key + ": " + g.Count() + "件");
}
C#GroupBy は「同じ TypeCode のものをまとめる」操作です。
- g.Key → グループのキー(ACTIVE / BALANCE / INDOOR)
- g.Count() → そのタイプの件数
最も多いタイプを調べる
var most = groups
.OrderByDescending(g => g.Count())
.FirstOrDefault();
C#これで「どのタイプが一番多いか」が分かります。
LINQ を使うメリット
コードが短く、意図が明確になる
for 文で書くと 10 行以上になる処理が、
LINQ なら 1〜2 行で書けます。
データ処理の“流れ”が読みやすい
OrderBy → Take → Where → Select
のように、「何をしたいか」がそのままコードに現れます。
配列・List・ファイル読み込み後のデータなど、何にでも使える
LINQ は「データの形」に依存しません。
List でも配列でも、同じように使えます。
10日目のまとめ
今日のキーワードを整理します。
List<T>
配列より柔軟なコレクション。Add で増やせる。
LINQ
データを検索・抽出・並べ替え・集計するための C# の仕組み。
OrderBy / Where / Take / Average
LINQ の基本操作。データ処理が直感的に書ける。
Result のリスト
ログを Result の List として扱うことで、
「意味のあるデータ」として操作できる。
LINQ とクラスの組み合わせ
Result のような“意味のある型”を作ると、
LINQ のコードがさらに読みやすくなる。
ここまで来ると、
「データを読み込み → オブジェクトに変換 → LINQ で処理 → 表示」
という、実用アプリの基本構造が身についています。
