SelectとSelectManyの違い

LinqSelectSelectManyの違いについて。

public static IEnumerable<TResult> Select<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, TResult> selector)
//                -------
public static IEnumerable<TResult> SelectMany<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, IEnumerable<TResult>> selector)
//                --------------------

これらの違いは、引数に指定する関数selectorの戻り値の型が、TResultかIEnumerable<TResult>かだけである。


Selectは、次のように動作する。

  1. Selectは、sourceの各要素を引数としてselectorを繰り返し呼び出す。
  2. selectorは、渡された要素を加工して返す。渡された要素の型はTSource、返す要素の型はTResult。
  3. Selectは、返された要素をまとめてIEnumerable<TResult>として返す。

これに対して、

  1. SelectManyは、sourceの各要素を引数としてselectorを繰り返し呼び出すところまでは同じ。
  2. selectorは、渡された要素から、ひとまとまりの要素を選択しIEnumerable<TResult>として返す。
  3. SelectManyは、返されたそれぞれのひとまとまりから各要素を取り出し、それらをまとめてIEnumerable<TResult>として返す。

これらのメソッドに、引数sourceとしてIEnumerable<IEnumerable<string>>型の値を、また引数selectorとして渡された引数をそのまま返す関数を使ってみる。

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

namespace SelectManySample
{
    class Program
    {
        static void Main(string[] args)
        {
            IEnumerable<IEnumerable<string>> listOfArrayOfString = new List<string[]>()
            {
                new string[] { "1-1" },
                new string[] { "2-1", "2-2" },
                new string[] { "3-1", "3-2", "3-3" }
            };

            IEnumerable<IEnumerable<string>> selectResult = listOfArrayOfString.Select(ReturnAsIs);
            IEnumerable<string> selectManyResult = listOfArrayOfString.SelectMany(ReturnAsIs);
        }

        static IEnumerable<string> ReturnAsIs(IEnumerable<string> arg)
        {
            return arg;
        }
    }
}

Selectは、次のように動作する。

  1. Selectは、source { { "1-1" }, { "2-1", "2-2" }, { "3-1", "3-2", "3-3" } } の各要素 { "1-1" }, { "2-1", "2-2" }, { "3-1", "3-2", "3-3" } を、順にselectorに渡す。
  2. selectorは、それをそのまま返す。
  3. Selectは、返された要素をまとめて { { "1-1" }, { "2-1", "2-2" }, { "3-1", "3-2", "3-3" } } として返す。

これに対して、SelectManyは、

  1. selectorに渡すものとselectorが返すものは同じ。
  2. SelectManyは、返されたそれぞれのひとまとまり { "1-1" }, { "2-1", "2-2" }, { "3-1", "3-2", "3-3" } から各要素 "1-1", "2-1", "2-2", "3-1", "3-2", "3-3" を取り出し、それらをまとめて { "1-1", "2-1", "2-2", "3-1", "3-2", "3-3" } として返す。

Selectはデータ構造の形を変えない。これに対してSelectManyはコレクションを1つ展開して平坦にする。

Selectはコレクションの各要素の操作に使う。これに対して、SelectManyはコレクションのコレクションの操作に使う。具体的には、

  1. あるコレクションのそれぞれの要素から、操作対象となるコレクションを選択し、
  2. 必要に応じて、操作対象のコレクションの各要素を加工し、
  3. 加工した要素をひとまとめにして返す。