C# の LINQ Any() で存在チェック — Count() > 0 との違いと All() / Contains() の使い分け
みなさんこんにちは!ヒロポンです!
コレクションに「該当する要素があるか」を調べたい時、つい list.Count() > 0 って書いてませんか??
俺も昔そうでした。動くんですよ、それでも。
でも Any() っていうそのものズバリのメソッドがある。
じゃあ何で Count() > 0 じゃダメなん?? Any() と何が違うん?
ここをちゃんと腑に落とすと、コレクション操作の見え方がちょっと変わります。
この記事は、Any() が「そもそも何のためにあるのか」から始めます。Count() > 0 との違い、さらに All() / Contains() の使い分けまで、業務SEが納得して選べるように積み上げていきます。
なぜ「存在するか」専用のメソッドがあるのか
そもそもの話から。
コレクションに対して俺らが聞きたいことって、実は2種類あります。
- 何個あるかを知りたい(個数が欲しい)
- 1個でもあるかを知りたい(あるかないかだけ知りたい)
Count() は前者。全部数えて個数を返すメソッドです。Any() は後者。「1個でもあれば true」を返すメソッド。
で、Count() > 0 で存在チェックするのは、「何個あるか全部数えてから、0 より多いか比べる」という遠回りをしてるわけです。
本当に聞きたいのは「あるかないか」だけなのに。
Any() は「あるかないか」だけに特化してる。だから無駄がない。
LINQ がわざわざ別メソッドを用意してるのは、この問いの種類が違うからなんですよね。
ここまでで分かったこと:
Count()は「個数」、Any()は「存在の有無」。聞きたいことが違うから、メソッドも分かれている。
Count() > 0 と Any() は実際に何が違うのか
概念は分かった。じゃあ動きとして何が違うのか。
using System;
using System.Collections.Generic;
using System.Linq;
var numbers = new List<int> { 1, 2, 3, 4, 5 };
// どちらも「要素があるか」を true で返す
bool exists1 = numbers.Count() > 0; // 全部数えてから 0 と比較
bool exists2 = numbers.Any(); // 1個見つけた時点で true
Console.WriteLine($"Count() > 0 : {exists1}");
Console.WriteLine($"Any() : {exists2}");
結果はどちらも True。返り値は同じです。
違うのは途中の動き。
Count() はコレクションを最後まで走査して個数を確定させます。Any() は1個見つけた瞬間に走査をやめる。これを短絡評価(short-circuit)と言います。
要素が5個なら大した差じゃない。
でも要素が100万個あって、しかも先頭にお目当てがあったら? Count() は100万個ぜんぶ数える。Any() は1個目で止まる。
ここで差がつきます。
ここまでで分かったこと: 返り値は同じでも、
Any()は途中で打ち切る。大きいコレクションほど効いてくる。
短絡評価の仕組みを目で見る
「1個目で止まる」を、実際に列挙の様子を出力して確かめてみます。

コードで列挙の足跡を出してみます。
// 列挙されるたびにログを出すシーケンス
IEnumerable<int> Numbers()
{
for (int i = 1; i <= 5; i++)
{
Console.WriteLine($" 列挙: {i}");
yield return i;
}
}
Console.WriteLine("● Any(x => x >= 3):");
bool found = Numbers().Any(x => x >= 3); // 3 を見つけたら止まる
Console.WriteLine($" → {found}");
Console.WriteLine("● Count(x => x >= 3) > 0:");
int cnt = Numbers().Count(x => x >= 3); // 最後まで数える
Console.WriteLine($" → {cnt > 0}");
実行結果:

Any() の方は「列挙: 1 / 2 / 3」で止まる。Count() の方は「列挙: 1 / 2 / 3 / 4 / 5」と最後まで走る。
同じ答えを出すのに、見てる量がぜんぜん違う!!
ここまでで分かったこと:
Any()は条件に合う最初の1個で列挙を打ち切る。Count()は全部見る。これが速度差の正体。
Any() / Any(述語) / All() / Contains() を使い分ける
存在チェックの仲間は Any() だけじゃありません。聞きたいことに応じて、こんな感じで4種類を使い分けます。
var fruits = new List<string> { "apple", "banana", "cherry" };
bool anyShort = fruits.Any(f => f.Length <= 5); // 条件に合うのが1個でもあるか
bool allShort = fruits.All(f => f.Length <= 6); // 全部が条件を満たすか
bool hasBanana = fruits.Contains("banana"); // 特定の値を含むか
Console.WriteLine($"Any(len<=5) : {anyShort}"); // apple/cherry が該当 → True
Console.WriteLine($"All(len<=6) : {allShort}"); // banana=6, cherry=6 → True
Console.WriteLine($"Contains : {hasBanana}"); // → True
Any()— 引数なしなら「空かどうか」、述語ありなら「条件に合うのが1個でもあるか」All(述語)— 全部が条件を満たすか。1個でも反例が出たら即 false(これも短絡評価)Contains(値)— 特定の値そのものを含むか。値の比較なので述語は要らない
整理すると、こんな感じになります。

ここまでで分かったこと: 1個でもあるかは
Any()、全部そうかはAll()、この値があるかはContains()。問いの形で選ぶ。
知っておきたい挙動の違い2つ
概念を腑に落とすと、引っかかりやすい挙動も「なるほど」で受け止められます。2つ挙げておきます。
All() は空のコレクションで true を返す
直感に反するやつ。
空のリストに All() を投げると、条件が何であろうと true が返ります。
var empty = new List<int>();
Console.WriteLine($"empty.Any() : {empty.Any()}"); // False(1個もない)
Console.WriteLine($"empty.All(x => x > 100): {empty.All(x => x > 100)}"); // True(反例がない)
実行結果:

これはバグじゃない。論理の話です。
「反例が1つもないなら、全部が条件を満たしていることにする」という決まり(空真・vacuous truth)。All() は「条件を破る要素を探して、見つからなければ true」という動きをします。空なら破る要素もないので true。
実務だと「空のリストに All() で判定したら、想定外に通ってしまった」が起きがち。
空チェックを先に Any() で入れると安全です。
IEnumerable を二重に列挙すると、毎回評価し直される
IEnumerable<T> は「結果の入れ物」じゃない。「走査すると結果を作る手順」です。
だから列挙するたびに中身が作り直されます。
int calls = 0;
// 列挙されるたびに calls を増やす自前イテレータ
IEnumerable<int> Source()
{
for (int i = 1; i <= 3; i++)
{
calls++;
yield return i;
}
}
var source = Source();
bool any = source.Any(); // 1個目で止まる → 1回ぶん走る
int count = source.Count(); // 最後まで数える → 頭から3回走り直す
Console.WriteLine($"Source の中身が走った回数: {calls}"); // → 4
Any() は1個目で止まるので1回、Count() は最後まで数えるので3回。合わせて Source() の中身が 4回 走ります。
source を変数に取っただけでは「評価済み」にはならない。ここ、地味に踏むやつ。
この挙動、『Effective C#』(Bill Wagner・訳書 p.172)の LINQ の章でも要点が突かれています。
走査のたびに新しい結果が得られるこの挙動は遅延評価 (lazy evaluation) と呼ばれます。
俺の解釈はこう。LINQ の結果は「いつ走査されるか」で姿を変える。
重い処理を Select に挟んだまま Any() や Count() を別々に呼ぶと、その重い処理が列挙のたびに走ってしまう。確定させたいなら .ToList() で一度実体化して、それを使い回すのが定石です。
ここまでで分かったこと:
All()の空真と、IEnumerableの遅延評価。どちらも「なぜそうなるか」を押さえれば事故らない。
俺の現場ではこう使ってる
業務系の画面で「選択された行が1つでもあるか」を判定する処理、めちゃくちゃ出てきます。
昔の俺は素直に dataGridView.SelectedRows.Count > 0 とか list.Count() > 0 で書いてました。動くから気にしてなかった。
転機は、ある一覧画面の案件。「該当データがあるかだけ見たいのに、裏で重い射影を毎回流してて表示がもたつく」やつでした。
原因の一つが、Count() で全件評価してたこと。
Any() に変えて、必要なら .ToList() で一度だけ実体化する形にしたら、もたつきが消えた。マジで効いた。
それ以来、存在を聞きたいだけなら Any()、個数が要る時だけ Count() と機械的に切り替えてます。
コレクションが小さければ体感差はない。けど「問いの形に合ったメソッドを選ぶ」と、読み手にも意図が伝わっていい感じなんですよね。
まとめ
Any() と Count() > 0 の違い、整理するとこうです。
- 聞きたいのが「あるかないか」なら
Any()— 1個見つけたら止まる短絡評価で無駄がない - 聞きたいのが「何個か」の時だけ
Count()— 個数そのものが要る場面に絞る Any(述語)で条件付きの存在、All(述語)で全件チェック(空集合は true になる点だけ注意)Contains(値)は特定の値の包含IEnumerableは列挙のたびに再評価される。重い処理を挟むなら.ToList()で一度実体化
「問いの形に合わせてメソッドを選ぶ」。これだけで、コードの意図が読み手に伝わるし、無駄な走査も減っていい感じに締まります。
よくある質問
Q1. Any() と Count() > 0、結局どっちが速いの?
存在を確認するだけなら Any() です。Any() は最初の1個で打ち切る短絡評価、Count() > 0 は全件を数えてから比較します。要素が多いコレクションほど差が開きます。個数そのものが必要な場面でだけ Count() を使ってください。
Q2. List の Count プロパティと Count() メソッドは違う?
違います。List<T>.Count はプロパティで、内部に保持している件数を即座に返すので O(1) です。一方 LINQ の Count() メソッドは IEnumerable を走査して数えることがあります(ICollection 実装なら最適化されますが)。List を直接扱うなら、存在チェックでも list.Count > 0 は速いです。ただし「意図が伝わる」点では Any() が読みやすいです。
Q3. All() が空のコレクションで true を返すのはなぜ?
「条件を破る要素が1つもなければ全部満たしているとみなす」という論理(空真・vacuous truth)だからです。All() は反例を探して、見つからなければ true を返します。空なら反例もないので true。意図せず通したくない時は、先に Any() で空チェックを入れてください。
Q4. Contains() で自作クラスの比較がうまくいかない時は?
Contains() は既定で参照の同一性(または Equals)で比較します。値で比較したい自作クラスは、IEquatable<T> を実装して Equals と GetHashCode を正しく定義するか、Contains のオーバーロードで IEqualityComparer<T> を渡してください。これで「中身が同じなら含む」と判定できます。
関連記事
- C# LINQ Select の3パターン — Any() の隣、LINQ で「取り出す・射影する」側の基本。セットで押さえると LINQ の地図が埋まる
- C# の文字列比較 == / Equals / StringComparison でハマる3箇所 — Contains() の等値比較とも地続き。文字列の「同じ」を正しく判定する話
- TypeScript for C#: LINQ と配列メソッドの対応表 — Any() は JavaScript の some()、All() は every()。C# の感覚で TS の配列メソッドを読む派生編
- EF6 で LINQ の N+1 問題を避ける — Any() が DB に投げると EXISTS になる話の応用。遅延評価が効いてくる現場
- SESの年収と単価を逆算する — 基礎を腑に落とせる SE は何が違うのか。技術の土台を、単価の話に繋げるキャリア編
以上!
「Count() > 0 で書いてたわ」って人いたら、どんどんシェア待ってるぜ!!
この記事の参考文献
ここまでの知見は以下の書籍から引用しています。業務SE視点で再構成していますが、元の体系的な知識を学ぶには直接読むのがおすすめです。
📖 『Effective C# 6.0/7.0』(著: Bill Wagner・訳書)
引用範囲: p.172(第4章 LINQ を扱う処理・遅延評価)
本の特徴: C# 開発者が押さえるべき50のベストプラクティス集。ボックス化 / LINQ / 例外処理 / 型設計 / Generics など、業務SEが C# で実装する際の判断軸を例示ベースで提示。Any() の裏にある遅延評価まで腹落ちさせたい人に効く。
こんな人におすすめ: C# 業務SE / .NET 開発者 / ASP.NET・WinForms 案件担当
執筆者
バイブス父さん — 業務SE 7年(SIer 正社員2 / フリーランス5)。現職は SEO 直轄部の AI アドバイザー兼 PL、副業で中小 SIer の CTO。SIer の正社員からフリーランスに転じ、複数のエージェント経由で案件を回してきた経験ベースで「業務SE視点」の技術 + キャリア記事を書いています。
🐦 X: @hiro_progra0524(日々の現場メモ更新中)
📝 About Me で経歴詳細を見る


コメント