こんにちは。ゆとり(@yutori_techblog)です。
先日、

WhereとSelectを同時に行いたい…
となりましたので、自作のLINQオペレータを作成して対応しました。
この記事では、WhereとSelectを同時に行える自作LINQオペレータを紹介します!
WhereとSelectを同時に行う方法
WhereとSelectを同時に行うためのLINQメソッドは、C#標準では用意されていません。
ではどうすれば良いか?
自作しましょう!
WhereとSelectを同時に行う自作LINQメソッド
下記コードをそのままコピーして、適当な静的クラスに格納してください。
public static IEnumerable<TResult> WhereSelect<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, (bool where, TResult select)> func)
{
return source.Select(item => func(item)) //抽出と変換を同時に行う
.Where(item => item.where) //抽出結果でフィルタリング
.Select(item => item.select); //変換結果を取得
}
使い方
基本的な使い方はいつものWhereやSelectと同じです。
違うのは、Whereに対する戻り値とSelectに対する戻り値を、両方とも返すメソッドを指定する点です。
collection.WhereSelect(key =>
{
bool where = dictionary.TryGetValue(key, out TValue select);
return (where, select);
})
このように、Whereに対する戻り値、Selectに対する戻り値を両方とも返すメソッドを指定します。
または、次のように簡潔に1行で書くこともできます。
collection.WhereSelect(key => (dictionary.TryGetValue(key, out TValue value), value));
どちらにせよ、WhereやSelectを単体で使うほどの直感性は失われていますが、使いどころによっては便利に使えると思います。
使用例:苗字から名前を探し出す
次の例は、Listに格納されている苗字を名簿の中から探し出し、名簿に存在する場合は名前を取得するプログラムです。
class Program
{
static void Main(string[] args)
{
//これらの苗字に合致するものを「名簿リスト」から探す
List<string> firstnameList = new List<string>()
{
"鈴木", "木村", "柴田", "加藤"
};
//WhereとSelectを同時に実行
var result = firstnameList.WhereSelect(first => (NameTable.TryGetValue(first, out string last), last));
//検索・変換結果を表示
foreach (var lastname in result)
{
Console.WriteLine(lastname);
}
}
/// <summary>
/// 名簿リスト
/// </summary>
private static Dictionary<string, string> NameTable = new Dictionary<string, string>()
{
{"山田", "花子" },
{"鈴木", "翔太" },
{"下出", "秀隆" },
{"佐藤", "佳澄" },
{"加藤", "麻結" }
};
}
実行結果

名簿に存在する苗字のみから、名前を取得できています。
まとめ
この記事では、LINQでWhereとSelectを同時に行う自作メソッドを紹介しました。
LINQの醍醐味である直感性が少々損なわれてしまうため乱用は禁物ですが、TryGetValueのように1つのメソッド結果から2つの値が出力される場合などには有効ではないでしょうか。
お役に立てましたら幸いです。