前回は「null(何も無い、が引き起こすエラー)」をやりました。

今回は、C#最大の魅力ともいわれるLINQ(リンク)です。これまでやってきた List や配列が、おどろくほど便利になります。

LINQ とは、データの絞り込みや並べ替えを、短く書ける仕組みです。

これまでの「探す・絞る」は、面倒だった

たとえば、点数のリストから「60点以上だけ」を取り出したいとします。これまでの知識だと、こう書きます。

List<int> scores = new List<int> { 80, 45, 95, 30, 70 };
List<int> passed = new List<int>();

foreach (int score in scores)
{
    if (score >= 60)
    {
        passed.Add(score);
    }
}
// passed = { 80, 95, 70 }

第12回〜13回でやった List・foreach・if の組み合わせです。ちゃんと動きますが、「60点以上を取り出す」だけなのに、けっこうな行数になります。

この「絞り込む」という、よくある作業を、ぐっと短く書けるのが LINQ です。

LINQ で書くと、こうなる

同じことを LINQ で書くと、1行です。

List<int> scores = new List<int> { 80, 45, 95, 30, 70 };

var passed = scores.Where(score => score >= 60);
// passed = { 80, 95, 70 }

Where(ホエア)が、LINQ の機能です。「条件に合うものだけを、取り出す」という意味。

形を見てみましょう。

scores.Where(score => score >= 60)
  • scores.Where(...) … scores の中から、条件に合うものを絞る
  • score => score >= 60 … 「各要素(score)について、60以上か?」という条件

=> は「ラムダ式」という書き方ですが、ここでは「それぞれの要素について、こういう条件」と読めば大丈夫です。「各 score について、score >= 60 のものだけ」ですね。

foreach も if も書かず、「60以上を絞る」という意図が、そのまま1行になりました。

いろいろな操作が、用意されている

LINQ には、よく使う操作が、たくさん用意されています。代表的なものを見てみましょう。

絞り込む(Where)

var passed = scores.Where(s => s >= 60);   // 60以上だけ

並べ替える(OrderBy)

var sorted = scores.OrderBy(s => s);       // 小さい順に並べる

個数を数える(Count)

int count = scores.Count(s => s >= 60);    // 60以上は何個?

合計する(Sum)・平均(Average)

int total = scores.Sum();                  // 合計
double avg = scores.Average();             // 平均

最大・最小(Max / Min)

int highest = scores.Max();                // 最高点

「絞る」「並べる」「数える」「合計する」——データに対してやりたいことが、ほとんど一言で書けます。

クラスと組み合わせると、本領発揮

LINQ が本当に強いのは、クラスのリストと組み合わせたときです。第18回以降で作った Person を思い出してください。

List<Person> people = new List<Person>
{
    new Person { Name = "山田", Age = 20 },
    new Person { Name = "田中", Age = 35 },
    new Person { Name = "佐藤", Age = 28 },
};

この中から「30歳以上の人の名前を、取り出す」のも、LINQ なら簡単です。

var names = people
    .Where(p => p.Age >= 30)     // 30歳以上を絞って
    .Select(p => p.Name);        // 名前だけ取り出す
// names = { "田中" }
  • Where で「30歳以上」を絞り
  • Select で「名前だけ」を取り出す

. でつないで、「絞って、取り出す」という流れが、そのまま書けます。データベースに「30歳以上の名前をください」とお願いするような感覚です。これが、業務でデータを扱うときに、ものすごく役立ちます。

なぜ LINQ が「魅力」なのか

LINQ の良さは、「どうやるか」ではなく「何がほしいか」を書けることです。

  • foreach + if … 「1つずつ見て、条件に合えば足して…」と手順を書く
  • LINQ … 「60以上のものがほしい」とほしいものを書く

手順を細かく書く代わりに、結果を宣言する。だからコードが短く、読みやすく、意図が伝わりやすい。これが、多くのC#プログラマーが LINQ を愛用する理由です。

つまずきポイント

LINQ は便利ですが、最初は =>(ラムダ式)の見た目に戸惑います。

scores.Where(s => s >= 60)

この s => s >= 60 は、「s という名前で各要素を受け取って、s >= 60 かを判定する」という、小さな関数です。

最初は「s => は『各要素について』という意味」とだけ覚えれば十分です。s の名前は何でもよく(score でも x でも可)、「各要素を、こう判定する/こう変換する」と読めれば、LINQ は使えます。

慣れるまでは、foreach で書いてもまったく問題ありません。「同じことが LINQ なら1行で書ける」と知っておいて、少しずつ使っていけば大丈夫です。

まとめ

LINQ は、データの絞り込みや並べ替えを、短く書ける仕組み。

var passed = scores.Where(s => s >= 60);    // 絞る
var sorted = scores.OrderBy(s => s);        // 並べる
int total = scores.Sum();                   // 合計

var names = people
    .Where(p => p.Age >= 30)                // 絞って
    .Select(p => p.Name);                   // 取り出す
  • foreach + if で書いていた処理が、一言で書ける
  • 「手順」ではなく「ほしいもの」を書ける
  • クラスのリストと組み合わせると、特に強力
  • s => は「各要素について」と読む

LINQ まで来れば、C#でできることが大きく広がります。データを自在に扱えるのは、業務系の開発で、とても大きな武器になります。