動くコード図鑑技術記事現場の渡り方キャリア論すべての記事About
技術記事

C#でLinqを使って特定の条件に一致するものをカウントする。

バイブス父さん
現役の業務SE
2020年10月27日7 min read
C#でLinqを使って特定の条件に一致するものをカウントする。

みなさんこんにちは!!

ヒロポンです!

今回はふと技術的な記事を書こうかなーーと思ったので、C#でみんな大好きLinqを使って、特定の条件に一致するものをカウントする超絶簡単なプログラムを紹介したいと思います!

普通にLinqを使う

💡 Linq の Count() がパフォーマンス問題になった場合は別記事 C# Linq で Null を回避する書き方とパフォーマンス でベンチ込みで書いてます。本番障害になりがちな罠です。

まずは普通にLinqを使って、特定の条件に一致するものをカウントしてみます。

普通にLinqを使う (csharp)#a45a64bd8cc9
            var strs = new List<string>()
            {
                "山田",
                "鈴木",
                "小林",
                "山岡",
                "小山",
                "鈴原"
            };
 
        var res = strs.Count(item => item.Contains("山"));
        Console.WriteLine(res);
▸ 実行ボタンで結果を表示

名前のリストがあってその中で山を含むものをカウントします。

実行すると3が返ります。

Linqの中で関数を使う

では別パターンでLinqの中で下記の関数を使ってみます。

Linqの中で関数を使う (csharp)#b20a1695e40b
        static bool IsContainYama(string str)
        {
            return str.Contains("山");
        }
▸ この snippet は実行結果未収録
▸ 実行結果は未収録です

山を含む場合はTrueを返すという単純な関数です。

Linq構文を下記のように書き換えます。

Linqの中で関数を使う (csharp)#5c3cab99527f
        static void Case2()
        {
            var strs = new List<string>()
            {
                "山田",
                "鈴木",
                "小林",
                "山岡",
                "小山",
                "鈴原"
            };
 
        var res = strs.Count(item => IsContainYama(item));
        Console.WriteLine(res);
    }
▸ 実行ボタンで結果を表示

結果は同じく3になります。

Linqに直接関数を投げる

ここまでは余裕ですが、ここから少しかっこいい感じになります。

Linq構文の中でitem => item == みたいな感じで書いていましたが、それすらも省略して書いていきます。

Linqに直接関数を投げる (csharp)#e71c6fab9d33
        static void Case3()
        {
            var strs = new List<string>()
            {
                "山田",
                "鈴木",
                "小林",
                "山岡",
                "小山",
                "鈴原"
            };
 
        var res = strs.Count(IsContainYama);
        Console.WriteLine(res);
    }
▸ 実行ボタンで結果を表示

デリゲート的な感じで関数をそのまま投げれます。

関数をそのまま投げるってイメージはJavaScriptとかを学ぶとはっきりわかるかと思います。その際にTypeScriptで勉強するとより深くわかります。

これを下記のような感じにするとコンパイルエラーが出ます。

            var res = strs.Count(IsContainYama());

これなんでかというと、C#は関数名+()で関数を実行するんですね。

なので今回関数名に()を付けるとその場で実行しようとしてバグってるわけです。

そもそもLinqの引き数は関数である。

そもそもLINQって中でどんな構文が書かれているかというと、下記のような感じです。

IEnumerable<特定の型>の拡張メソッドとして用意されており、その特定の型を引数でBoolが返る関数を第二引数にしているわけです。

なので直接関数を投げてもコンパイルエラーが出ることなく通ったわけですね!!

Linqに直接関数を投げると存在チェックもお手の物

ちなみに存在チェックのAny関数も引数は同じです。

なので、Count部を変更するだけでBool値を取得することができます。

            var res = strs.Any(IsContainYama);
            Console.WriteLine(res);

結果は下記!

今回のコードgitに上げてます!

今回のコードを下記urlからクローンしてもらえば、今回の動作をローカルで見てみることができます!

https://github.com/adaman3568/blog-source-demo

💡 補足: 業務系の現場でよくハマるパターン

俺もこの Linq の Count() パターン、業務でハマったところがあります。3つ紹介します。

① List.Count プロパティ vs Enumerable.Count() を混同

List<T>.Count は O(1) のプロパティアクセスだが、 IEnumerable<T>.Count() は O(n) で全件走査します。 foreach 内で list.Count() を呼ぶと O(n²) になる罠。100行 OK、10万行で死にます。 Linq パフォーマンス記事 でベンチ取ってます。

② IEnumerable を二度回す → 二度クエリ走る

EntityFramework や DbSet を直接 Where → Count + Where → ToList と呼ぶと、 SQL が2回飛びます。 .ToList() でマテリアライズしてから Count するのが定石。N+1問題の親戚。

③ null 要素混在で例外

list.Count(x => x.Name == "foo") で x が null だと NRE。 ?. 演算子で防御。詳しくは Linq の Null 回避 で書いてます。

❓ よくある質問

Q1. Count() と Count プロパティどっちを使うべき?

A. コレクションが List/Array なら Count プロパティ(O(1))。 IEnumerable や Linq の結果なら Count() メソッド。 .Net 6+ の TryGetNonEnumeratedCount なら自動判別します。

Q2. Any() と Count() > 0 どっちが速い?

A. Any() です。1件見つけた時点で打ち切るので、 Count() > 0 より圧倒的に速い。「存在チェック」目的なら必ず Any()

Q3. Linq の Count() は SQL の COUNT() と同じ?

A. EntityFramework / Linq2SQL なら SQL に変換されます。 in-memory コレクションへの Count() は C# 側で実行。 LinqProvider 次第で挙動が変わるので、 ToList() 後か前かを意識する必要あり。

Q4. GroupBy + Count の組み合わせ方は?

A. list.GroupBy(x => x.Category).Select(g => new { g.Key, Count = g.Count() }) が定石。 SQL の GROUP BY ... COUNT(*) と同等。 DataTable LINQ 3パターン で実例書いてます。

Q5. Linq の Count() のオーバーロードは何種類?

A. 2種類。引数なし版(全件カウント)と Predicate 版(条件マッチ件数)。 list.Count(x => x.IsActive) のように書ける。 Where().Count() と等価ですが Count(predicate) の方がコンパクト。

📚 関連記事

執筆者

バイブス父さん — 業務 SE 7 年 (正社員 2 / フリーランス 5)。 現職は SEO 直轄部の AI アドバイザー兼 PL、 副業で中小 SIer の CTO。 SES 複数社・フリーランスエージェント複数経由の経験ベースで「業務 SE 視点」 の技術 + キャリア記事を書いています。

🐦 X: @hiro_progra0524 (日々の現場メモ更新中)
📝 About Me で経歴詳細を見る

この記事のコードと手順は ぜんぶ動作検証済み。 安心して現場で試してくれ。
バイブス父さん

現役の業務SE。C# / SQL Server 保守の現場から、コードも人もキャリアも全部書く。 実体験ベース。

運営者について