記事内に広告が含まれています

【ワテのC#講座】LINQの基本を覚える【初心者向け】

この記事は約18分で読めます。
スポンサーリンク

ワテの場合、LINQと言う奴が苦手だ。

LINQ (Language-Integrated Query)

 

WikipediaによるとLINQとは以下の通り。

統合言語クエリ (LINQ, Language INtegrated Query, リンクと発音する)とは、.NET Framework 3.5において、様々な種類のデータ集合に対して標準化された方法でデータを問い合わせる(クエリ)ことを可能にするために、言語に統合された機能のことである。

開発ツールはVisual Studio 2008から対応している。

引用元 https://ja.wikipedia.org/wiki/統合言語クエリ

まあ、この説明を読んでもLINQを使った事が無い人にはチンプンカンプンだと思う。

ワテの理解では、LINQとは平たく言えば、配列やリストのデータを従来ならforループを使って加工していたが、それを一つの式として記述するやり方だ。

マイクロソフトのサイトにもLINQに関して各種の情報がある。
例えばここ。

LINQ (Language-Integrated Query) – MSDN – Microsoft

当記事では、LINQ初心者のワテがLINQの入門講座を書いてみた。

ちなみに、ワテの場合はその後、猛烈にLINQを勉強したので、今ではこんな処理をLINQでやりたいなあと思った事は、ほぼ自力でLINQ式を記述出来る。

では、本題に入ろう。

スポンサーリンク
スポンサーリンク

データから部分集合を取り出す通常の処理(forループ方式)

例えば、プログラミングをしていて何らかのデータのリストや配列が有った場合に、その部分集合を取り出したいという状況は良くある。

普通の方法なら、forループで回して条件にマッチしたデータのみを部分集合として取り出す。簡単な場合なら3行程度のforループで書ける。あるいは、条件が複雑になると何十行のコードになる場合もある。

例えば元データから部分集合を取り出すのだが、さらに不要なメンバーは除去して特定のメンバーのみ残した部分集合などを作成したいなどの状況だ。

そういう処理を普通のforループで行おうとすると、事前に結果データを入れる為のデータ型を定義しておくなどが必要になる場合もある。

データから部分集合を取り出す処理をLINQでやる

一方、LINQと言うのを使うとそう言う何十行もの処理を一行で書けるのだ。

例えば、こんなデータが有ったとしよう。

元データ(東京都の都議会議員の名簿)

--元データ--
1000      内田茂       千代田区      自
1001      立石晴康      中央区       自
1002      菅野弘一      港区        自
1003      きたしろ勝彦    港区        自
1004      吉倉正美      新宿区       公
1005      大山とも子     新宿区       共
1006      秋田一郎      新宿区       自
1007      大門さちえ     新宿区       自
1008      中屋文孝      文京区       自
1009      小竹ひろ子     文京区       共
1010      中山ひろゆき    台東区       民
1011      和泉ひろし     台東区       自
1012      川松真一朗     墨田区       自
1013      加藤雅之      墨田区       公
1014      桜井浩之      墨田区       自

引用元 http://www.gikai.metro.tokyo.jp/membership/electoral_zone.html

今、何かと話題の多い東京都の都議会議員の名簿の一部だ。

選挙区別名簿

から拝借したものだ。

数字はワテが勝手に振った通し番号なので深い意味は無い。

東京都の都議会議員の名簿に対してやりたい事

やりたい事は、この議員名簿から新宿区選出の議員を取り出したい。

上表の緑字で塗った人達だ。

全部で四名。

さらに、必要なのは緑字の名前選挙区のデータのみ(下図)。

番号   名前      選挙区   政党

従って、番号の数字や政党(自公民共)などのデータは除去したい。

これらの処理で取り出したいデータは以下の通りとなる。

取り出したいデータ(結果データ)

吉倉正美      新宿区
大山とも子     新宿区
秋田一郎      新宿区
大門さちえ     新宿区

これをLINQでやると、簡単に一行で書けるのだ。

実際にやってみよう。

C#のLINQで東京都議会議員名簿を処理する

即席で下に示すC#コードを作成した。

Visual Studioで作成したコンソールアプリケーションだ。

各議員の情報データがPersonというクラスに保管されていて、それをリストにして全議員の情報を保持している。

それが元データだ。

その元データに対して、四通りのLINQ式を記述してみた。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace LINQ_ConsoleApp
{
 
    class Program
    {
        public class Person
        {
            public int id;
            public string name;
            public string address;
            public string party;
            public Person(int id, string name, string address, string party)
            {
                this.id = id;
                this.name = name;
                this.address = address;
                this.party = party;
            }
        }
 
 
        static void Main(string[] args)
        {
            List<Person> people = new List<Person>
            {
                // 東京都議会 選挙区別議員名簿(一部)
                new Person (1000"内田茂"       ,"千代田区","自"),
                new Person (1001"立石晴康"     ,"中央区"  ,"自"),
                new Person (1002"菅野弘一"     ,"港区"    ,"自"),
                new Person (1003"きたしろ勝彦" ,"港区"    ,"自"),
                new Person (1004"吉倉正美"     ,"新宿区"  ,"公"),
                new Person (1005"大山とも子"   ,"新宿区"  ,"共"),
                new Person (1006"秋田一郎"     ,"新宿区"  ,"自"),
                new Person (1007"大門さちえ"   ,"新宿区"  ,"自"),
                new Person (1008"中屋文孝"     ,"文京区"  ,"自"),
                new Person (1009"小竹ひろ子"   ,"文京区"  ,"共"),
                new Person (1010"中山ひろゆき" ,"台東区"  ,"民"),
                new Person (1011"和泉ひろし"   ,"台東区"  ,"自"),
                new Person (1012"川松真一朗"   ,"墨田区"  ,"自"),
                new Person (1013"加藤雅之"     ,"墨田区"  ,"公"),
                new Person (1014"桜井浩之"     ,"墨田区"  ,"自")
            };
            Console.WriteLine("--元データ--");
            foreach (var x in people)
            {
                Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}", x.id, x.name, x.address, x.party);
            }
 
 
 
            //var aa = people.Select(x => x.address.Equals("新宿区")).ToList();
            Console.WriteLine("--result1--");
            {
                var result1 = people.Where(x => x.address.Equals("新宿区")).ToList();
 
                foreach (var x in result1)
                {
                    Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}", x.id, x.name, x.address, x.party);
                }
            }
 
 
            Console.WriteLine("--result2--");
            {
                var result2 = people.Where(x => x.address.Equals("新宿区"))
                        .Select(x => new
                        {
                            address = x.address,
                            name = x.name
                        });
 
                foreach (var x in result2)
                {
                    Console.WriteLine("{0,-10}{1,-10}", x.name, x.address);
                }
            }
 
            Console.WriteLine("--result3--");
            {
                var result3 = from x in people
                              where x.address.Equals("新宿区")
                              select new
                              {
                                  address = x.address,
                                  name = x.name
                              };
 
                foreach (var x in result3)
                {
                    Console.WriteLine("{0,-10}{1,-10}", x.name, x.address);
                }
            }
 
            Console.WriteLine("--result4--");
            {
 
                var result4 = from x in people
                              where x.address.Equals("新宿区")
                              select new List<string>
                     {
                          x.address,
                          x.name
                     };
 
                foreach (var x in result4)
                {
                    Console.WriteLine("{0,-10}{1,-10}", x[0], x[1]);
                }
            }
        }
    }
}

LINQにも何通りかの書き方があるようなので、ここではワテが知っている奴を使ってみた。

C#のLINQ式の実行結果は以下の通り

--result1--
1004      吉倉正美      新宿区       公
1005      大山とも子     新宿区       共
1006      秋田一郎      新宿区       自
1007      大門さちえ     新宿区       自
--result2--
吉倉正美      新宿区
大山とも子     新宿区
秋田一郎      新宿区
大門さちえ     新宿区
--result3--
吉倉正美      新宿区
大山とも子     新宿区
秋田一郎      新宿区
大門さちえ     新宿区
--result4--
新宿区       吉倉正美
新宿区       大山とも子
新宿区       秋田一郎
新宿区       大門さちえ
続行するには何かキーを押してください . . .

以下、簡単な説明。

result1の場合

var result1 = people.Where(x => x.address.Equals("新宿区")).ToList();

この場合は、新宿区にマッチしたデータを加工せずにそのまま取り出して部分集合リストを作成している。

なので除去したいと思っているIDと政党名のデータもresult1に入っている。

result2の場合

  var result2 = people.Where(x => x.address.Equals("新宿区"))
               .Select(x => new
               {
                     address = x.address,
                     name = x.name
               });

一行ちゃうやんと言う人もいるかもしれないが、見やすくするために改行しているだけなので、コマンドとしては一行だ。実際、末尾のセミコロン ; は文末に一個しかない。

一番目の例との違いは、Selectを追加して、特定の要素を持つ新しいデータを作成している。

Visual Studioのローカルウインドウでresult2の中身を見てみると、最初の要素は以下の通り。

- 結果ビュー 結果ビューを展開すると、IEnumerable が列挙されます。
- [0] { address = "新宿区", name = "吉倉正美" }      <Anonymous Type>
        address "新宿区" string
        name "吉倉正美" string

データ型が<Anonymous Type>とか言う良く分からんデータタイプになっている。

その中身は、string型のデータが二個入っている。

result3の場合

ワテが最初に覚えたのは最初の例 result1やresult2 のようWhereやSelectをドット . で連結する方式だった。

この記述方法をメソッド構文LINQと言う。

でもそれとは別に、SQL文を記述するように記述するLINQがある。

この例ではそれを使っている。

 var result3 = from x in people
               where x.address.Equals("新宿区")
               select new
                {
                      address = x.address,
                      name = x.name
                };

処理結果は result2 と同じになる。

このSQL文のような記述方法の何が良いのかは当初は分からなかったが、LINQをある程度使いこなせるようになった今では、この記述方法も時々使う。

ちなみに、この記述方法をクエリ構文LINQと言う。

クエリ構文LINQのメリットしては、ワテの経験では、データベースの操作でSQL文を使いこなせる人にはそれと同じ感覚でLINQ式を記述出来るので、それが便利なのだと思う。

なお、メソッド構文LINQとクエリ構文LINQとで出来る事は同じだと思う。

どちらかの方式のほうが、より細かく条件指定ができるので良いと言うような事実は、ワテが知る限り無いようだ。

ちなみに、このresult3の中身も<Anonymous Type>になっている。

result4の場合

 var result4 = from x in people
               where x.address.Equals("新宿区")
               select new List<string>
               {
                    x.address,
                    x.name
               };

result3でselectの部分をList<string>に変更してみた。

- 結果ビュー 結果ビューを展開すると、IEnumerable が列挙されます。
- [0] Count = 2   System.Collections.Generic.List<string>
        [0] "新宿区" string
        [1] "吉倉正美" string

その結果、出力データはList<string>に変わった

まあ、当然だな。

LINQの出力結果を新しいクラスに入れたい場合

ここまで書いていて、では出力結果を新しいデータ形式Person2クラスに入れたい場合にはどうするのかな?と言う疑問が出てきた。

Person2クラスは以下のように定義しておく。

public class Person2
{
    public string name;
    public string address;
}

そうすると、以下のようにすると、

Console.WriteLine("--result5--");
{
 
    var result5 = from x in people
                  where x.address.Equals("新宿区")
                  select new Person2()
                  {
                      address = x.address.ToString(),
                      name = x.name.ToString()
 
                  };
 
    foreach (var x in result5)
    {
        Console.WriteLine("{0,-10}{1,-10}", x.name, x.address);
    }
}

LINQの結果をPerson2に入れる事が出来た。

- 結果ビュー 結果ビューを展開すると、IEnumerable が列挙されます。
- [0] {LINQ_ConsoleApp.Program.Person2}  LINQ_ConsoleApp.Program.Person2
         address "新宿区"   string
         name "吉倉正美"    string

こんな感じか。

LINQを使うと何が良いのか?

あくまでワテの個人的な感想であるが、必要なデータを取り出す為に、徐々に条件を与えて絞り込んで行くので、各段階で確認しながらLINQを作成すると間違いが入り込む余地が少ない。

一方、forループを使う従来方式なら、処理をだらだらと記述するので当然ではあるが、バグが入り込む可能性が高い。

そう言う点では正しく記述したLINQでは、一行の命令なのでバグが入り込む余地も少なく、正常に動けば一発で結果が得られるし、異常があると例外などが出るので分かり易い。

 

LINQの欠点としては、後でコードを見直したときに、自分でも何の処理をしているのか分からなくなる場合がある。ましてや他人が書いた複雑なLINQを解読するのは難しいかもしれない。

なのでLINQを使う場合でも、比較的分かり易い文法を使うようにしている。

まとめ

まあ、ワテは滅多にLINQを使わない主義だったのだが(主義と言うよりは、苦手だったので使えなかったと言うのが正しい)、最近は、時代の流れに付いて行く為に、LINQを使うようにしている。

使ってみると中々便利やん。

2018/3/19

その後、ワテもLINQを使いこなせるようになり、今では従来式のforループなんて使うよりもLINQでバンバン書くようになった。

理由は、慣れるとLINQのほうが使い易いのだ。

なぜなら、LINQは一つの式なので、SQL文を駆使して徐々にデータを絞り込んで加工すると、自分が必要とする結果に収束する。そう言う処理の流れが気分爽快なのだ。

皆さんにもLINQをお勧めしたい。

アマゾンで本を買う

ネットの情報によると、この本は、初心者の人が取り合えずVisual Studioの使い方を覚えて、兎に角プログラムを作ってみる入門書としては良い本らしい。

しかし、ワテは読んでいないのでその噂の真偽の程は未確認だ。

スポンサーリンク
コメント募集

この記事に関して何か質問とか補足など有りましたら、このページ下部にあるコメント欄からお知らせ下さい。

C#Visual Studio生活
スポンサーリンク
シェアする
warekoをフォローする
スポンサーリンク

コメント