LINQの考え方

2022年1月6日

データの塊から何かを得たい場合、例えば、XXより大きいものを集める。XXより小さいものを集めるなどのコードを書く場合、for文やif文を思い描くと思います。練習課題に出てきそうな要件ですね。多分、20行〜30行で書けるでしょうか?これを4〜5行にまとめられたらすごいと思いませんか?LINQを使うとそれができます。ただ、for文、if文でせっかくかけているのに?って思いませんか?それは、for文、if文からの変遷を知らないからなのです。そこがわかれば、「なんだ、if文、for文関係してるんだ」って理解が深まります。

コードを短くしたい

長いコードを短くするには?を考えてみましょう

[ 50, 10, 30, 40, 100, 1000, 1 ] というデータのグループで40より大きいのだけ見つけたい

LISTを作る

まず、データの塊を作ろう。

  • 変数名は、scores(スコアーズ)にする。
  • 中身は、50,10,30,40,100,1000,1という整数。
static void Main(string[] args)
{
    var scores = new List<int> { 50, 10, 30, 40, 100, 1000, 1 };
}

コンソール画面に全部表示してみよう。
scores内から、1つずつ取り出してscore変数に代入。それを表示することをなくなるまで繰り返す。

static void Main(string[] args)
{
    foreach (var score in scores)
    {
        Console.WriteLine(score);
    }
}

絞り込み(フィルター)

データ(scores)の中から、40より大きなものを探して、別のListに代入していこう。

static void Main(string[] args)
{
    var selectLarger40 = new List<int>();
    foreach (var num in scores)
    {
        if (num > 40)
        {
            selectLarger40.Add(num);
        }
    }
}

処理をメソッドにしてみる

この部分をメソッドにしてみよう。元のデータの塊を引数にして、戻り値は、結果のデータの塊にしよう。

VisualStudioで、メソッドの抽出を実行してみた。

static void Main(string[] args)
{
    NewMethod(scores);
}
private static void NewMethod(List<int> scores)
{
    var selectLarger40 = new List<int>();
    foreach (var num in scores)
    {
        if (num > 40)
        {
            selectLarger40.Add(num);
        }
    }
}

メソッド名をSelectLarger40にして、戻り値をList<int>にしよう。return値も必要です。

static void Main(string[] args)
{
    SelectLarger40(scores);
}
private static List<int> SelectLarger40(List<int> scores)
{
    var selectLarger40 = new List<int>();
    foreach (var num in scores)
    {
        if (num > 40)
        {
            selectLarger40.Add(num);
        }
    }
    return selectLarger40;
}

mainメソッド側で、戻ってきたListを変数に代入できるようになったので、結果をもらおう。

static void Main(string[] args)
{
    List<int> newScores;
    newScores = SelectLarger40(scores);
}
private static List<int> SelectLarger40(List<int> scores)
{
    var selectLarger40 = new List<int>();
    foreach (var num in scores)
    {
        if (num > 40)
        {
            selectLarger40.Add(num);
        }
    }
    return selectLarger40;
}

mainメソッドは、宣言と代入を同時にして、1行にまとめてみよう。

static void Main(string[] args)
{
    var newScores = SelectLarger40(scores);
}
private static List<int> SelectLarger40(List<int> scores)
{
    var selectLarger40 = new List<int>();
    foreach (var num in scores)
    {
        if (num > 40)
        {
            selectLarger40.Add(num);
        }
    }
    return selectLarger40;
}

ここまでをまとめると

static void Main(string[] args)
{
    var scores = new List<int> { 50, 10, 30, 40, 100, 1000, 1 };
    var newScores = SelectLarger40(scores);
    foreach (var num in newScores)
    {
        Console.WriteLine(num);
    }
}
private static List<int> SelectLarger40(List<int> scores)
{
    var selectLarger40 = new List<int>();
    foreach (var num in scores)
    {
        if (num > 40)
        {
            selectLarger40.Add(num);
        }
    }
    return selectLarger40;
}

結果は?うまくいっているようだ。

50
100
1000

 Press any key to continue...

「40より大きい」を30とか50とかにも変更できるようにメソッドの引数を増やしてみよう。

static void Main(string[] args)
{
    var scores = new List<int> { 50, 10, 30, 40, 100, 1000, 1 };
    var newNumbers = SelectLarger(scores, 40);
    foreach (var num in newNumbers)
    {
        Console.WriteLine(num);
    }
}
private static List<int> SelectLarger(List<int> numbers,int comp)
{
    var selectLarger40 = new List<int>();
    foreach (var num in numbers)
    {
        if (num > comp)
        {
            selectLarger40.Add(num);
        }
    }
    return selectLarger40;
}

コードを短くできればいいなー

ただ比較しているだけなのに、なんかコードが長いなー

scores(40より大きいのだけにする)

なんてできるといいのに。
そのまま、メソッドの宣言部分(シグネチャ)を入れてみたら・・

scores(List<int> SelectLarger(List<int> numbers, int comp))

戻り値とメソッド部分が見分けづらいなー
=> こんなのを入れてみて、numbersを渡していることを書いておこう

scores((List<int> numbers) => (SelectLarger(List<int> numbers, int comp)))

結果を戻してくれるのがわかればいいから、メソッドの名前もいらないなー
戻してくれるという意味でreturnを書いて、numbersの内、comp以上のものだけという意味で、 numbers > compとして・・・

scores((List<int> numbers) => (return(List<int> numbers > int comp)))

型名は、C#の推論機能でわかるだろうから、省略と・・・

scores((numbers) => (return(numbers > comp)))

おお、だいぶん短くなったきた(勝手にしたが・・・)
いっそのこと、returnもいらないか・・・

scores((numbers) => (numbers > comp))

引数1つだし、もう、ついでに()もいらないだろう

scores(numbers => (numbers > comp))

もう一声、右辺の()も取っちゃえ

scores(numbers => numbers > comp)

いい感じだ。〜より大きいデータを取り出す!処理をWhereと名付けよう。

scores.Where(numbers => numbers > comp)

これを当てはめると・・・

static void Main(string[] args)
{
    var scores = new List<int> { 50, 10, 30, 40, 100, 1000, 1 };
    var newNumbers = scores.Where(numbers => numbers > 40);
    foreach (var num in newNumbers)
    {
        Console.WriteLine(num);
    }
}
private static List<int> SelectLarger(List<int> numbers, int comp)
{
    var selectLarger40 = new List<int>();
    foreach (var num in numbers)
    {
        if (num > comp)
        {
            selectLarger40.Add(num);
        }
    }
    return selectLarger40;
}

完成形!!

最初に作ったメソッドをバッサリと・・・

static void Main(string[] args)
{
    var scores = new List<int> { 50, 10, 30, 40, 100, 1000, 1 };
    var newNumbers = scores.Where(numbers => numbers > 40);
    foreach (var num in newNumbers)
    {
        Console.WriteLine(num);
    }
}

結果!!!

50
100
1000

 Press any key to continue...

C#

Posted by hidepon