LINQで選択肢の全組み合わせ展開の続き。
選択肢数が可変でもOK!とするために再帰でやったけど、
選択肢数も型も決まってるんなら、こっちの方がスマートかと。
というわけで実装。
クエリ式で実装
SQLで全組み合わせ作る時に、結合条件なしで直積を作ってたよね、ってことで、
クエリ式でもjoinを使わずに、選択肢の数だけ**「from~in~」**を並べて全組み合わせを展開。
その後で、重複が無いものだけを引っこ抜く。
Program.cs
public static void Main(string[] args)
{
var items = new int[] { 1, 2, 3 };
//結合条件なしで重複ありの全組み合わせを展開
//展開結果は配列にする
//q1{1,1,1}{1,1,2}{1,1,3}{1,2,1}…{3,3,3}
var q1 = from s1 in items
from s2 in items
from s3 in items
select new int[] { s1, s2, s3 };
//各要素の重複なしのレコードのみ抽出して返す
//要素の個数と、各要素の値の種類数が一致していれば重複無しと判断
// q1={1,3,1}の場合、要素の個数は3、値の種類数は2(1と3しかないから)→×:除外
// q1={1,3,2}の場合、要素の個数は3、値の種類数は3→○:抽出
// q1={1,1,1}の場合、要素の個数は3、値の種類数は1(1しかないから)→×:除外
var q2 = q1.Where(ar => ar.Length == ar.Distinct().Count());
q2.DisplayElement<int>();
}
実行結果確認用のコード
結果確認用の拡張メソッド。(前回作ったそのままでよかったね。。。)
Extention.cs
/// <summary>
/// 結果表示用
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query"></param>
public static void DisplayElement<T>(this IEnumerable<T[]> query)
{
foreach (var q in query)
{
Console.WriteLine(string.Join(" ", q));
}
}
実行結果
おっけー!
修正前
albireoさんからアドバイスをいただき、修正しました。修正前は↓。
Selectの射影を匿名型で取る意味ってなかったね。。。
修正前のコード
【修正前】Program.cs
public static void Main(string[] args)
{
var items = new int[] { 1, 2, 3 };
//結合条件なしで重複ありの全組み合わせを展開
//q1{1,1,1}{1,1,2}{1,1,3}{1,2,1}…{3,3,3}
var q1 = from s1 in items
from s2 in items
from s3 in items
select new { N1 = s1, N2 = s2, N3 = s3 };
//各要素の重複なしのレコードのみ抽出して返す
//要素の個数と、各要素の値の種類数が一致していれば重複無しと判断
// q1={1,3,1}の場合、要素の個数は3、値の種類数は2(1と3しかないから)→×:除外
// q1={1,3,2}の場合、要素の個数は3、値の種類数は3→○:抽出
// q1={1,1,1}の場合、要素の個数は3、値の種類数は1(1)→×:除外
var q2 = q1.Where(v =>
{
var ar = new int[] { v.N1, v.N2, v.N3 };
return ar.Length == ar.Distinct().Count();
}
);
q2.DisplayElement();
}