C# の LINQ で絞り込む Where

Where は LINQ で最も基本的なメソッドだ。条件に合う要素だけを抽出する、いわゆるフィルタリング処理を行う。

基本的な使い方

条件を満たす要素だけを取り出す。

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

var evenNumbers = numbers.Where(n => n % 2 == 0);

foreach (var n in evenNumbers)
{
    Console.WriteLine(n);  // 2, 4, 6, 8, 10
}

Where にはラムダ式で条件を渡す。この条件を「述語(predicate)」と呼ぶ。述語が true を返した要素だけが結果に含まれる。

オブジェクトのフィルタリング

数値だけでなく、オブジェクトのプロパティで絞り込むことも多い。

var people = new List<Person>
{
    new Person { Name = "Alice", Age = 25 },
    new Person { Name = "Bob", Age = 30 },
    new Person { Name = "Charlie", Age = 35 },
    new Person { Name = "Diana", Age = 28 }
};

// 30歳以上の人を抽出
var adults = people.Where(p => p.Age >= 30);

foreach (var person in adults)
{
    Console.WriteLine($"{person.Name}: {person.Age}");
}
// Bob: 30
// Charlie: 35

プロパティにアクセスして条件を指定できる。複雑なオブジェクトでも同様に扱える。

複数条件の組み合わせ

&&|| で複数の条件を組み合わせられる。

var people = new List<Person>
{
    new Person { Name = "Alice", Age = 25, City = "Tokyo" },
    new Person { Name = "Bob", Age = 30, City = "Osaka" },
    new Person { Name = "Charlie", Age = 35, City = "Tokyo" },
    new Person { Name = "Diana", Age = 28, City = "Tokyo" }
};

// 東京在住かつ30歳未満
var result = people.Where(p => p.City == "Tokyo" && p.Age < 30);

foreach (var person in result)
{
    Console.WriteLine(person.Name);  // Alice, Diana
}

論理演算子を使えば、どんな複雑な条件でも表現できる。

Where の連鎖

Where を複数回連鎖させることもできる。

var numbers = Enumerable.Range(1, 100);

var result = numbers
    .Where(n => n % 2 == 0)   // 偶数
    .Where(n => n % 3 == 0)   // かつ3の倍数
    .Where(n => n > 10);       // かつ10より大きい

foreach (var n in result)
{
    Console.WriteLine(n);  // 12, 18, 24, 30, ...
}

これは && で繋いだ一つの Where と同じ結果になる。可読性のために分けることもあるが、通常は一つの Where にまとめた方がシンプルだ。

インデックス付きの Where

要素のインデックスを条件に使いたい場合は、オーバーロードを使う。

string[] fruits = { "apple", "banana", "cherry", "date", "elderberry" };

// インデックスが偶数の要素だけ
var result = fruits.Where((fruit, index) => index % 2 == 0);

foreach (var fruit in result)
{
    Console.WriteLine(fruit);  // apple, cherry, elderberry
}

ラムダ式の第二引数にインデックスが渡される。配列の偶数番目だけを取り出すといった処理に使える。

該当なしの場合

条件に合う要素がない場合、Where は空のシーケンスを返す。例外は発生しない。

int[] numbers = { 1, 2, 3, 4, 5 };

var result = numbers.Where(n => n > 100);

Console.WriteLine(result.Count());  // 0
Console.WriteLine(result.Any());    // False

空かどうかは Any() で確認できる。結果を使う前にチェックしておくと安全だ。