.net column

.NET開発者のためのブログメディア

C#のLINQにチャレンジしてみよう!

2020年05月07日

SE
C#のLINQは、どのような利用方法があるのでしょうか?

PM
さまざまな利用方法があるので、SQLを知らない人でも理解できるように解説していきましょう。

C#のLINQとは?

C#のLINQとはLanguage-Integrated Queryの略で、配列変数やコレクションなどのデータ群から、条件文を指定してそれに合うデータを取り出す構文を意味します。データベースで使うSQLに似ていますが、違いもあります。この記事ではSQLを知らない人でも理解できるようにわかりやすくご説明しますので、是非読んで役立ててください。

LINQの基本

まずは簡単な例から始めましょう。なおC#のLINQを使用するには、ソースコードの先頭にネームスペース指定の””using System.Linq;””を記述してください。int[] ary = { 8, 4, 2, 9, 5, 0, 3, 1, 7, 6 };// LINQクエリ構文var result = from val in ary where val <= 5 select val;// resultの中身を表示するforeach (var num in result){ Console.Write(num + “” “”);}これを実行すると、コンソールに以下のように表示されます。ary配列の5以下の値が抽出されていますね。4 2 5 0 3 1

クエリ構文とメソッド構文

上のサンプルプログラムのLINQクエリ構文の説明は以下になります。var result(結果を入れるresultコレクション)= from val in ary(配列aryの値を1つvalに入れる) where val &lt= 5(valが5以下であれば) select val;(valをresultに入れる)C#のLINQはSQLに似ていると言いましたが、selectを最後にするのがSQLと違います。なおサンプルのクエリ構文は以下のようなメソッド構文にすることも可能です。=>はC#特有のラムダ式の表記法ですね。var result = ary .Where(val => val <= 5) .Select(val => val);この記事では、ラムダ式を使用しないシンプルなクエリ構文で説明します。

匿名型でLINQを使う

C#の匿名型に対してLINQを使うと分かりやすいコードを記述できます。以下が例です。// 匿名型の配列var human_table = new[]{ new {FirstName = “”太郎””, SecondName = “”山田””, Age = 23, Sei = “”male”” }, new {FirstName = “”花子””, SecondName = “”鈴木””, Age = 18, Sei = “”female”” }, new {FirstName = “”一郎””, SecondName = “”佐藤””, Age = 41, Sei = “”male”” }, new {FirstName = “”信介””, SecondName = “”阿部””, Age = 32, Sei = “”male”” },};var result = from row in human_table where row.Sei == “”male”” // 男性のみ対象 orderby row.Age // 年齢で昇順にソート select row.SecondName; // セカンドネームを選択foreach (var name in result){ Console.WriteLine(name);}実行すると以下のように表示されます。山田阿部佐藤

orderbyで昇順・降順のソートが可能

上のサンプルプログラムは名簿のうち男性だけをリストアップしてセカンドネームを取り出し、年齢の若い順(昇順)に並べて表示するという処理を行います。クエリ構文のorderbyで昇順にソートされます。では降順にソートしたい場合はどうすれば良いのでしょうか。その場合は、orderby row.Age descendingとすれば年齢の高い順(降順)に表示されます。なお昇順の場合は以下のようにしてもOKです。ascendingは省略できるということですね。orderby row.Age ascending

intoでselect文を続ける

C#のクエリ構文はselectで終わりますが、その後にintoを追加するとさらに続けることができます。上のサンプルのクエリ文は以下のように記述しても同じ結果になります。var result = from row in human_table where row.Sei == “”male”” select row into row2 // intoでさらに続ける orderby row2.Age select row2.SecondName;「男性をリストアップして、そのリストをさらに年齢の昇順でソートする」ということですね。この例では元のクエリより複雑になっていますが、クエリの条件が多い場合は役立つでしょう。

letでクエリの中で変数の代入が可能

letを使うとクエリ内で変数の計算と代入ができます。サンプルのクエリを以下のように修正してみてください。var result = from row in human_table where row.Sei == “”male”” orderby row.Age let fullname = row.SecondName + row.FirstName // 名字と下の名前を結合 select fullname; // resultにフルネームを入れる結果は以下になります。山田太郎阿部伸介佐藤一郎

クエリの中でも匿名クラスを生成できる

クエリの中でnewをして匿名クラスを生成することができます。サンプルのクエリ以降を以下のように修正してみてください。var result = from row in human_table where row.Sei == “”male”” orderby row.Age select new { row.SecondName, row.FirstName }; // 名字と下の名前を返すforeach (var name_set in result){ Console.WriteLine(name_set.SecondName+name_set.FirstName); // 結合して表示}これで上でletを使った時と同じ結果が表示されます。letを使うより、このようにクエリの外で計算をした方がやりやすい場合もあるでしょう。

Count、Max、Averageなどの使い方

C#のLINQのクエリは数値の項目に対して計算をすることもできます。以下はサンプルのhuman_tableの項目について様々な計算を行います。// データの項目の数var cnt = (from row in human_table select row.SecondName).Count();Console.WriteLine(“”人数は ”” + cnt + “”人””);// 項目の最大値var max = (from row in human_table select row.Age).Max();Console.WriteLine(“”最高年齢は ”” + max + “”才””);// 項目の平均値var avg = (from row in human_table select row.Age).Average();Console.WriteLine(“”平均年齢は ”” + avg + “”才””);結果は以下になります。他にも最小値を出すMin()や合計値を出すSum()もあるので試してみてください。人数は 4人最高年齢は 41才平均年齢は 28.5才

AnyとAllの使い方

取得したデータが条件を満たすかどうかチェックするにはAnyとAllを使います。以下はサンプルのhuman_tableの項目について判定を行います。判定文の=>はラムダ式ですね。// Anyの条件を1つでも満たせばTruebool result1 = (from row in human_table select row.Age).Any(age => age < 20);Console.WriteLine(“”20歳未満がいるかどうか ”” + result1);// Allの条件を全て満たせばTruebool result2 = (from row in human_table select row.Age).All(age => age >= 20);Console.WriteLine(“”全員が20歳以上かどうか ”” + result2);結果は以下になります。human_tableの鈴木花子さんが18歳なのでAnyの条件はTrue、Allの条件はFalseになるということですね。20歳未満がいるかどうか True全員が20歳以上かどうか False

SelectManyで配列を取得できる

匿名型の配列にさらに配列が入っていた場合、それを取得するには以下のようにSelectManyを使います。なおLINQのこの機能はクエリ型でなくメソッド型で使用します。var syumi_table = new[]{ new {SecondName = “”山田””, Syumi = new[]{ “”サッカー””,””ゲーム”” } }, new {SecondName = “”鈴木””, Syumi = new[]{ “”ピアノ””,””読書”” } }, new {SecondName = “”佐藤””, Syumi = new[]{ “”ゴルフ””,””カラオケ”” } }, new {SecondName = “”阿部””, Syumi = new[]{ “”バンド””,””競馬”” } },};var result = syumi_table .Where(val=> val.SecondName != “”鈴木””) .SelectMany(val=> val.Syumi); // Syumiを全て取得foreach (var list in result){ Console.WriteLine(list);}このサンプルを実行すると以下のように表示されます。配列の中身がIEnumerableを実装しているコレクションとして取得されています。サッカーゲームゴルフカラオケバンド競馬

joinで2つのデータを結合

joinを使うと2つのデータの共通点がある項目を結合することができます。ここまでのサンプルでhuman_tableとsyumi_tableという2つの匿名型の配列データが出てきましたが、これを結合してみましょう。join~in~on~equals~で可能です。以下がその例です。var result = from row in human_table join row2 in syumi_table on row.SecondName equals row2.SecondName select new[] { row.FirstName, row2.Syumi[0] };foreach (var name_syumi in result){ Console.WriteLine(name_syumi[0]+”” “”+name_syumi[1]);}human_tableとsyumi_tableのSecondNameは共通しているので、それが等しい箇所を結合します。実行すると以下のように表示されます。太郎 サッカー花子 ピアノ一郎 ゴルフ信介 バンド

group byで重複する箇所のあるデータをまとめる

例えばサンプルのsyumi_tableが以下のようになっていたら、SecondNameが同じ個所をまとめたいと思いますよね。var syumi_table = new[]{ new {SecondName = “”山田””, Syumi = “”サッカー”” }, new {SecondName = “”山田””, Syumi = “”ゲーム”” }, new {SecondName = “”鈴木””, Syumi = “”ピアノ”” }, new {SecondName = “”鈴木””, Syumi = “”読書”” },};group byを使えば同じ箇所があるデータをまとめることができます。以下が例です。var result = from row in syumi_table group row.Syumi by row.SecondName; // SecondNameでSyumiをまとめる foreach (var name_syumi in result){ Console.Write(name_syumi.Key+”” “”); foreach (var s in name_syumi) { Console.Write(s+”” “”); } Console.WriteLine(“”””); // 改行}結果は以下になります。resultはIGroupingを実装したコレクションで、中身の要素のKeyにgroup byでまとめたSecondNameが入っています。山田 サッカー ゲーム鈴木 ピアノ 読書

SE
これならC#のLINQをマスターできそうです。

PM
C#でデータ検索のプロフェッショナルを目指すなら必須スキルなので、しっかりマスターしておきましょう!

さいごに

C#のLINQについて理解できましたでしょうか。今回のサンプルでは匿名クラスの配列データが対象でしたが、LINQは他にもXMLドキュメントやSQLデータベースを対象にすることもできます。C#でデータ検索のプロフェッショナルを目指すなら、是非LINQをマスターましょう。


.NET分野でのキャリアアップをお考えの方は、現在募集中の求人情報をご覧ください。

求人一覧

また、直接のエントリーも受け付けております。

エントリー(応募フォーム)