[C# LINQ] Whereの使い方から注意点まで

with コメントはまだありません

LINQの中でフィルタリングを司るWhereの使い方と使用上の注意を解説する。

 

Whereの役割

Whereの役割はコレクションをフィルタリングすることだ。例えば数字の入った配列があったとして、その中から偶数だけを取り出したいときなどに使える。

役割が単純な分使いやすく、使用機会も多い。これは裏を返せばつい無駄なところでも使ってしまうということ。今回の記事の後半ではWhereを使わなくても良いパターンを紹介する。

 

Whereの仕様と具体例 1

さて、Whereの仕様を見てみよう。Whereには2つのオーバーロードがあるが、まずはシンプルなこちらから。

コレクション(source)に対し、その要素(predicateの引数)をフィルターに通すかどうか(predicateの返り値)を記述する。入力と出力が非常にハッキリしていて分かりやすい。predicateが取る引数はコレクションの一要素で、この要素がフィルタリング条件にマッチしているならtrue、そうでないならfalseを返すようpredicateを書こう。

今、Nameというプロパティを持つPersonなるクラスがあり、Tanakaという名前の人でフィルタリングする場合を考えるとこうなる。

先ほど紹介したように、personを引数にとり、person.NameがTanaka、すなわちTanakaという名前の人だけをフィルターに通すよう指定した。

メソッド形式で書いてもクエリ形式でも結果は同じだけれど、個人的にはメソッド形式の方が使いやすいように感じる。

 

Whereの仕様と具体例 2

次に紹介するWhereのオーバーロードは先程のものより少し複雑になっている。

違いはpredicateが第二引数として要素のインデックスを取るということだ。コレクションをフィルタリングするとき、要素のインデックスを条件にしたいときがたまにある。そんな時にこちらのWhereを使おう。

 

先ほどの具体例と同じくPersonクラスのインスタンスを複数持つPeopleというコレクションをフィルタリングしてみよう。二番目以降(インデックスが1以上)の人だけを取り出してみる。

 

Whereを使わなくてもいいパターン3つ

このようにお手軽にフィルタリングが出来るWhereだけれど、使わなくてもいいパターンが存在する。それは、Whereと他のメソッドを組み合わせる時だ。一つづつ見ていこう。

 

条件に合う要素の数を数える – Count

フィルタリングにマッチした要素の数を数えるときが一つ目。Tanakaという名前の人が何人いるかを数えたいとき、要素の数を数えるCountというメソッドと組み合わせるとこうなる。

フィルタリングして(Where)、数を数える(Count)。とても素直なコードだと思うけれど、実はWhereは無くてもいい。Countにフィルタリング条件を指定できるからだ。

このようにCountを呼び出すだけで良くなる。

「Whereでフィルタリング条件を指定しなくていい=Whereがいらない」という点はこの後でも紹介するパターンでも同じだ。

 

条件に合う要素を1つだけ取得する – First / FirstOrDefault

LINQの中でかなり出現頻度が高いのがこのパターンだ。Whereと同じLINQメソッドであるFirstあるいはFirstOrDefaultを使えば、コレクションの最も先頭の要素を取得できる。これをWhereと組み合わせ、「フィルタリング後のコレクションから先頭要素だけを取ればいいんじゃん!」となるけれどここでお立ち会い。先ほどの例と同じく、First / FirstOrDefaultにも直接フィルタリング条件を指定できるのだ。

Firstは要素がないときに例外を飛ばし、FirstOrDefaultはnullを返す。コレクションに要素があるかどうか(あるいはフィルタリング条件に合った要素があるかどうか)は分からないため、極力FirstOrDefaultを使うことをオススメする。Firstが原因のバグをいくつ見てきたことか……。

 

条件に合う要素があるかを判定する – Any

コレクションに要素があるかどうかを判定するAnyなるLINQメソッドがある。これをWhereと組み合わせれば、条件に合う要素があるかどうかが分かると思うかもしれない。それはその通りだけれど、例のごとくAnyに条件を指定できる。

 

余談 ResharperやRiderならLINQのアンチパターンを指摘してくれる

我々エンジニアは覚えることが多い。その上このようなアンチパターンを一々覚えていくのは大変じゃないだろうか? TOACHでも何回か紹介しているResharperやRiderを使えば、このようなLINQのアンチパターンを指摘してくれる。ResharperはVisual Studioの拡張機能で、C#開発を爆速にしてくれる。Riderは、Resharperの開発元であるJetBrains社が提供している、C#専用のクロスプラットフォームIDEだ。

例えばWhere + CountをCountだけにできるケース。Riderを使えば問題箇所に下線を引いて、ポップアップで改善案「Countだけにしようぜ〜」ということを言ってくれる。その上、改善まで自動でやってくれるから驚きだ。

where-count-to-count

C#erなら足を向けては寝られないJetBrains。そしてそのプロダクトであるResharperとRider。これを紹介した記事はこちら。

Rider : 期待度MAXな次世代のC#開発環境 Rider を使ってみた。

Resharper : [永久保存版] C#のイマドキな開発環境はこれなのですぞ

 

LINQの豊富な実用例を知りたい人にはこれがオススメ