C# Tips | コレクション・LINQ:件数カウント

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

はじめに:「件数カウント」は“システムの現状を数字でつかむ道具”

業務システムでは、常に「いま何件あるか?」が問われます。

未処理の件数
エラー件数
今日登録された件数

これをコードで表現するのが「件数カウント」です。
C# / LINQ では Count を中心に、とてもシンプルに書けますが、
「どこで数えるか」「どう数えるか」を間違えると、性能やバグに直結します。

ここから、初心者向けに

Count の基本
条件付きカウント
null 安全なカウント
Distinct や GroupBy と組み合わせたカウント

を順番にかみ砕いていきます。


基本:Count で「要素の数」を数える

単純なコレクションの件数を数える

一番シンプルな例からいきます。

using System;
using System.Collections.Generic;
using System.Linq;

var numbers = new List<int> { 1, 2, 3, 4, 5 };

int count = numbers.Count();

Console.WriteLine(count); // 5
C#

Count() は「列の要素数」を返します。
List<T> や配列、IEnumerable<T> なら、基本的にどれでも使えます。

ここでの重要ポイントは、「Count() は“今の時点での件数”を返す」ということです。
コレクションの中身が変われば、Count() の結果も変わります。

空のコレクションでも 0 を返す

var empty = new List<string>();

int count = empty.Count();

Console.WriteLine(count); // 0
C#

空でも例外にはならず、0 が返ってきます。
「0 件」というのは、業務的にもよくある“普通の状態”なので、
Count() が例外ではなく 0 を返してくれるのは、とても扱いやすいです。


条件付きカウント:Count(predicate) を使う

「条件に合うものだけ」の件数を数える

「全件数」ではなく、「条件に合う件数」を知りたいことがほとんどです。

例えば、「偶数の件数」を数えてみます。

var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

int evenCount = numbers.Count(x => x % 2 == 0);

Console.WriteLine(evenCount); // 3
C#

Count(x => 条件) は、「条件が true になる要素だけを数える」という意味です。

ここでの重要ポイントは、「Where(...).Count()Count(...) はほぼ同じ意味だが、Count(...) のほうが意図がはっきりする」ことです。

// どちらも「偶数の件数」
numbers.Where(x => x % 2 == 0).Count();
numbers.Count(x => x % 2 == 0);
C#

「件数を知りたい」ときは、Count(predicate) を素直に使うほうが読みやすくなります。

社員の「営業部の件数」を数える

社員クラスを用意します。

public class Employee
{
    public int No { get; set; }
    public string Name { get; set; } = "";
    public string Department { get; set; } = ""; // "Sales", "Dev", ...
}
C#

データを作ります。

var employees = new List<Employee>
{
    new Employee { No = 1, Name = "Sato",   Department = "Sales" },
    new Employee { No = 2, Name = "Suzuki", Department = "Dev" },
    new Employee { No = 3, Name = "Tanaka", Department = "Sales" },
};
C#

営業部の人数を数えます。

int salesCount = employees.Count(e => e.Department == "Sales");

Console.WriteLine(salesCount); // 2
C#

ここでの重要ポイントは、「業務の問いをそのまま Count の条件にする」ことです。
「部署が Sales の社員の件数」→ Count(e => e.Department == "Sales")
という対応が、そのまま読めるようになります。


null 安全な件数カウント

null かもしれない List の件数を数える

業務コードでは、List<T>? が null のこともあります。
そのまま list.Count() と書くと、NullReferenceException になります。

安全に書くなら、こうです。

List<string>? names = GetNamesOrNull();

int count = names?.Count() ?? 0;

Console.WriteLine(count);
C#

names?.Count() は、names が null のときは null を返し、
?? 0 で「null なら 0 にする」という意味になります。

ここでの重要ポイントは、「null のときは“0 件”として扱うのか、“エラー”として扱うのかを決める」ことです。
多くのケースでは、「null =データなし」とみなして 0 件にするほうが扱いやすいです。

null 安全な拡張メソッドを用意する

毎回 ?.Count() ?? 0 と書くのが面倒なら、
ユーティリティとして拡張メソッドを作っておくのも手です。

public static class CountExtensions
{
    public static int SafeCount<T>(this IEnumerable<T>? source)
    {
        return source?.Count() ?? 0;
    }
}
C#

使い方はこうです。

List<string>? names = GetNamesOrNull();

int count = names.SafeCount();
C#

ここでの重要ポイントは、「境界で null を吸収してしまう」ことです。
内部のロジックでは「件数は常に 0 以上の整数」として扱えるようになります。


Distinct と組み合わせて「ユニーク件数」を数える

「顧客の種類の数」を数える

売上明細がたくさんあるとき、
「顧客の種類が何社あるか」を知りたいことがあります。

public class Sale
{
    public string Customer { get; set; } = "";
    public int Amount { get; set; }
}
C#

データを用意します。

var sales = new List<Sale>
{
    new Sale { Customer = "A", Amount = 1000 },
    new Sale { Customer = "B", Amount = 2000 },
    new Sale { Customer = "A", Amount = 3000 },
};
C#

顧客の種類数(ユニーク件数)を数えます。

int customerCount = sales
    .Select(s => s.Customer)
    .Distinct()
    .Count();

Console.WriteLine(customerCount); // 2
C#

ここでの重要ポイントは、「Select でキーを取り出し、Distinct で重複を消してから Count する」という流れです。
「ユニークな値の件数」を数えたいときの定番パターンです。


GroupBy と組み合わせて「グループごとの件数」を数える

部署ごとの社員数を出す

グルーピングと件数カウントは、セットで使うことが多いです。

var result = employees
    .GroupBy(e => e.Department)
    .Select(g => new
    {
        Department = g.Key,
        Count      = g.Count()
    });

foreach (var x in result)
{
    Console.WriteLine($"{x.Department}: {x.Count} 人");
}
C#

ここでの重要ポイントは、「g.Count() は“そのグループに属する件数”」だということです。
グルーピング → グループごとの件数、という流れは、集計処理の基本パターンになります。


パフォーマンスの話を少しだけ

Count と Any の使い分け

「1件でもあるかどうか」だけ知りたいときに、
Count() > 0 と書くのは、あまり良くありません。

// あまり良くない
if (items.Count() > 0) { ... }
C#

Count() は、列を最後までなめて件数を数えます。
要素が 1 件でも 100 万件でも、全部見に行きます。

「1件でもあればいい」なら、Any() を使うほうが効率的です。

if (items.Any()) { ... }
C#

Any() は、1件見つかった時点で処理を止めてくれます。

ここでの重要ポイントは、「件数が欲しいのか、“あるかどうか”だけ知りたいのか」を意識してメソッドを選ぶことです。
「あるかどうか」なら Any、「何件あるか」なら Count です。


実務で意識してほしいこと

「何の件数か」をコードにハッキリ書く

件数カウントは、変数名がとても大事です。

count だけだと、「何の件数?」が分かりません。
totalCount, salesCount, errorCount, pendingCount のように、
「何を数えた件数なのか」が分かる名前をつけてください。

int pendingCount = orders.Count(o => o.Status == "Pending");
C#

これだけで、コードの意図が一気に読みやすくなります。

「0 件」を特別扱いしない設計にする

Count() は 0 を返してくれるので、
「0 件だから例外」「0 件だから null」という設計にする必要はありません。

0 件は普通の状態として扱い、
画面側で「該当するデータはありません」と表示するなど、
“0 件でも破綻しない”設計にしておくと、全体が安定します。


まとめ:「件数カウントユーティリティ」は“状態を数字で語るための基礎体力”

件数カウントの本質は、
「システムの状態を、数字という形で正確に把握する」ことです。

押さえておきたいポイントは、

Count() で全件数、Count(predicate) で条件付き件数を数える
null かもしれないコレクションは ?.Count() ?? 0SafeCount で扱う
ユニーク件数は SelectDistinctCount
グループごとの件数は GroupByg.Count()
「あるかどうか」だけなら Count() > 0 ではなく Any()

このあたりを自分の中で“当たり前の道具”にしておくと、
「なんとなく数えている」状態から抜けて、
“業務の問いにきちんと答えられる件数カウント”を書けるようになります。

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