2

SelectMany拡張メソッドのみを使用して3つ以上のシーケンスのクロス結合を取得するために適用する最良の方法は何ですか?クロスジョインを取得する他の方法はありますか?

テストデータ

var a = Enumerable.Range(11, 2);
var b = Enumerable.Range(21, 2);
var c = Enumerable.Range(31, 2);

期待される結果

 X  Y  Z 

11 21 31 
11 21 32 
11 22 31 
11 22 32 
12 21 31 
12 21 32 
12 22 31 
12 22 32 

私が試したこと

動作するコードは次のとおりですが、読みやすく理解しやすい代替手段があるかどうか疑問に思います。

var d = a
    .SelectMany(rb => b
    .SelectMany(rc => c, (y, z) => new { Y = y, Z = z}), 
                        (x, yz) => new { X = x, Y = yz.Y, Z = yz.Z });

同等のクエリ式は適切ですが、私が探しているものではありません。

var e = from x in a
        from y in b
        from z in c
        select new { X = x, Y = y, Z = z };
4

3 に答える 3

3

SelectManyこの方法でクエリを単純化できます(それほど多くはありませんが) 。

var res = a.SelectMany(X => b.SelectMany(Y => c.Select(Z => new { X, Y, Z })));
于 2012-12-01T13:41:24.653 に答える
1

Join常に一致するキーを投影するを使用できます。

var e = a.Join(b, x => true, y => true, (x, y) => new { A = x, B = y })
         .Join(c, x => true, y => true, (x, y) => new { x.A, x.B, C = y });

SelectMany確かに、それはおそらくあなたのバージョンよりも効率的ではありません。

于 2012-12-01T12:59:57.523 に答える
1

カスタムメソッドを作成してもよいかどうかはまだわかりません。しかし、ここにとにかくあります:

public static IEnumerable<IEnumerable<T>> CrossJoin<T>(params IEnumerable<T>[] sequences)
{
    IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };
    foreach (var sequence in sequences)
    {
        result = result.SelectMany(i => sequence.Select(s => i.Concat(new[] { s })));
    }
    return result;
}

このようなメソッドを追加すると、重要なコードが非常に読みやすくなります。

var d = CrossJoin(
    Enumerable.Range(11, 2),
    Enumerable.Range(21, 2),
    Enumerable.Range(31, 2)
);

結果:

Console.WriteLine("X  Y  Z");
foreach( var item in d ) {
    Console.WriteLine(String.Join( ",", item ));
}
/*
X  Y  Z
11,21,31
11,21,32
11,22,31
11,22,32
12,21,31
12,21,32
12,22,31
12,22,32
*/
于 2012-12-01T14:38:38.877 に答える