C# ゼロから理解するラムダ式:C#でLINQのSelectの使い方を解説 #15

前回の記事ではLINQで最も使うといっても過言ではないWhereメソッドについて解説しました。前回の記事は「C# ゼロから理解するラムダ式:C#でLINQのWhereの使い方を解説 #14」から確認することができます。

今回も前回に引き続きLINQについて学びます。Whereメソッドに引き続いて学んでおくべきは「Selectメソッド」になります。このSelectもよく使うのでLINQの基礎として押さえておいた方がよいですね。

Selectメソッドの基礎知識

まずはSelectメソッドの基礎知識から紹介していきます。SelectメソッドはMicrosoftの公式ホームページでは以下のように記述されているメソッドになります。

要素のインデックスを組み込むことにより、シーケンスの各要素を新しいフォームに射影します。

重要な部分は「新しいフォームに射影します。」の部分ですね。要するにSelectメソッドの括弧内に渡されたFuncの内容で新しいコレクションを作成するという意味になります。

また、Selectメソッドで作成されたコレクションは遅延実行により実装されるため、別インスタンスで使用したい場合はToArrayやToListメソッドを使用する必要があることに注意しましょう。

Selectメソッドを書く方法

では早速Selectメソッドを実際に書いていきたいと思います。新規のコンソールアプリケーションを作成して、以下のアプリケーションを作成してみてください。

using System;
using System.Linq;

namespace App16
{
    class Program
    {
        static void Main(string[] args)
        {
            var numList = Enumerable.Range(1, 10);

            //Selectメソッドを使用する
            var newList = numList.Select(x => x * x);

            foreach(var item in newList)
            {
                //コンソール画面に出力する
                Console.WriteLine(item.ToString());
            }
            Console.ReadLine();
        }
    }
}

上記のアプリケーションでは以下のように出力されているはずです。

1
4
9
16
25
36
49
64
81
100

Selectメソッドの括弧内のラムダ式に注目してみてください。ラムダ式は以下のようになっており、Funcの形式となっています。型推論により戻り値はint型となります。

var newList = numList.Select(x => x * x);

引数である「x」は「numList」の各要素ですのでint型となります。「=> x * x」の部分は「xとxを掛け算して、その計算結果を戻り値とする」ため、int型 * int型 = int型となります。このFuncは引数がint型で戻り値もint型になるということです。

処理内容が「x * xを戻り値とする」ため、新規で射影されるコレクションは各要素の二乗を格納する内容となります。そのため「1, 4, 9, 16, 25…」となっているのです。Selectが新しいコレクションを作るという意味がよく分かりますね。

SelectManyメソッドを書く方法

Selectと別バージョンとして「SelectManyメソッド」というものがあります。これもよく使うメソッドなので当記事で触れておきたいと思います。このメソッドは公式では以下のように記述されています。

シーケンスの各要素を IEnumerable に射影し、結果のシーケンスを 1 つのシーケンスに平坦化します。

「平坦化」という聞きなれないワードがあるかと思います。「平坦化」とはコレクション内に格納されたコレクションのプロパティを抜き取って、別のコレクションにするという意味になります。以下、サンプルを使用して紹介します。

using System;
using System.Collections.Generic;
using System.Linq;

namespace App17
{
    class Program
    {
        public class Menu
        {
            public List<int> Prices { get; set; }
            public string Name { get; set; }
        }

        static void Main(string[] args)
        {
            var menues = new List<Menu>()
            {
                new Menu(){ Name="唐揚げ", Prices=new List<int>(){ 250, 300, 450 }, },
                new Menu(){ Name="たこ焼き", Prices=new List<int>(){ 320, 380, 400 }, },
                new Menu(){ Name="イカ焼き", Prices=new List<int>(){ 280, 320, 480 }, },
            };

            //シーケンスからPricesプロパティだけ取得して平坦化する
            var newList = menues.SelectMany(x => x.Prices);
            foreach(var item in newList)
            {
                Console.WriteLine(item);
            }
            Console.ReadLine();
        }
    }
}

各Menuクラスの要素からPricesというコレクションのプロパティを抜き取って一つのコレクションに平坦化した例です。出力結果は以下のようになります。各要素を重複なく宣言したのでどの要素から取得したのか分かると思います。

250
300
450
320
380
400
280
320
480

SelectManyメソッドはコレクションの各要素に含まれるコレクションを平坦化する処理ですが、これも使う場面がありそうでしたので紹介しておきました。データ構造がコレクションのネスト構造であれば、SelectManyメソッドを使用してデータを一回で取得できるので活用してみてください。

以上、ここではSelectメソッドとSelectManyメソッドを解説しました。Selectメソッドは別のコレクションに射影する処理をしてくれます。特定の処理を付与して別のコレクションを作成することができる機能なので覚えておきましょう。