生成n-ary Cartesian产品示例

我发现Eric Lippert的post适合我遇到的一个特殊问题。

问题是我无法理解我应该如何使用2个以上的集合。

var collections = new List<List>(); foreach(var item in somequery) { collections.Add( new List { new MyType { Id = 1} .. n } ); } 

如何在变量集合中应用笛卡尔积linq查询?

扩展方法是这样的:

 static IEnumerable<IEnumerable> CartesianProduct(this IEnumerable<IEnumerable> sequences) { IEnumerable<IEnumerable> emptyProduct = new[] { Enumerable.Empty()}; return sequences.Aggregate( emptyProduct, (accumulator, sequence) => from accseq in accumulator from item in sequence select accseq.Concat(new[] {item}) ); } 

这是Eric的2个集合的例子:

 var arr1 = new[] {"a", "b", "c"}; var arr2 = new[] { 3, 2, 4 }; var result = from cpLine in CartesianProduct( from count in arr2 select Enumerable.Range(1, count)) select cpLine.Zip(arr1, (x1, x2) => x2 + x1); 

示例代码已经能够执行“n”笛卡尔积(在示例中它为3)。 您的问题是当您需要IEnumerable>时,您有一个List> IEnumerable>

 IEnumerable> result = collections .Select(list => list.AsEnumerable()) .CartesianProduct(); 

由于ListIEnumerable ,因此使用Eric解决方案的问题解决如下:

 var collections = new List>(); var product = collections.CartesianProduct(); foreach(var collection in product) { // a single collection of MyType items foreach(var item in collection) { // each item of type MyType within a collection Console.Write(item); } } 

当然,您可以以更简洁的方式聚合每个集合中的项目,例如作为单个string

 var product = collections .CartesianProduct() .Select(xs => xs.Aggregate(new StringBuilder(), (sb, x) => sb.Append(x.ToString()), sb => sb.ToString())); foreach(var collectionAsString in product) { Console.WriteLine(collectionAsString); }