LINQでクロス結合

クロス結合(CROSS JOIN)はLINQを使ってどうやって書くんだろうと気になったので調べてみました。

SQLでもほとんど使わないのでC#でもほとんど使わないとは思いますが・・・。重複ありのすべての組合わせを出したいときに使えるかなーと思います。まぁほとんど使わないんですが。

T-SQLでクロス結合

まずはSQLでサンプルを書いてみます。

-- 性別テーブル
if object_id('tempdb..#Gender') is not null drop table #Gender;
select *
into #Gender
from (values(N'男性'), (N'女性')) as Temp(Gender);
select * from #Gender;
/*
Gender
------
男性
女性
*/

-- 年代テーブル
if object_id('tempdb..#Year') is not null drop table #Year;
select *
into #Year
from (values(N'10代'), (N'20代'), (N'30代')) as Temp(Year);
select * from #Year;
/*
Year
----
10代
20代
30代
*/


-- クロス結合
select *
from #Gender cross join #Year;
/*
Gender Year
------ ----
男性     10代
男性     20代
男性     30代
女性     10代
女性     20代
女性     30代
*/

クロス結合を使うと、性別と年代の重複ありの組合わせを作ることができます。

LINQでクロス結合

LINQで同じことをするにはSelectManyを使うといいみたいです。

Enumerable.SelectMany メソッド (System.Linq)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp {
    class Program {
        static void Main(string[] args) {
            var genders = new [] { "男性", "女性" };
            var years = new [] { "10代", "20代", "30代" };

            // クロス結合
            var entries = genders.SelectMany(
                gender => years, // gendersの各要素に対して常にyearsを返す
                (gender, year) => new { Gender = gender, Year = year } );
            foreach (var entry in entries) {
                Console.WriteLine("{0} {1}", entry.Gender, entry.Year);
            }
            /*
           男性 10代
           男性 20代
           男性 30代
           女性 10代
           女性 20代
           女性 30代
           */
        }
    }
}

gendersの各要素ごとに呼び出されるcollectionSelector関数で常にyearsを返すという感じです。

他に良い方法があるのかしら。