C# | 2週間で身につくアプリを作りながら学ぶC#の基本 - 11日目

C# C#
スポンサーリンク

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 で処理 → 表示」
という、実用アプリの基本構造が身についています。

タイトルとURLをコピーしました