问题描述
现在,如果在编译时已知笛卡尔积的数量,那么我可以执行以下操作(对于3个笛卡尔积):
public static void Main(string[] args)
{
int[] numSet = {1,2,3,4};
var cartesianProduct = from letter in numSet
from number in numSet
from colour in numSet
select new { num1,num2,num3};
}
现在,我已经看到了这个答案:https://stackoverflow.com/a/4073806/5859885,它似乎提供了一种处理可变数量的集合的方法。方法如下:
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,(accumulator,sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item }));
}
现在,我将其应用于以下问题(这适用于4个笛卡尔乘积(请参见for循环),但是可以很容易地用可变数量笛卡尔乘积的方法包装))
static void Main(string[] args)
{
int[] numSet= new int[] { 1,4};
List<int[]> numList = new List<int[]>();
for(int i=0; i<4; i++)
{
numList.Add(numSet);
}
IEnumerable<IEnumerable<int>> combArray = CartesianProduct(numList);
foreach(var combo in combArray)
{
Console.WriteLine(combo);
}
}
现在,它可以编译,但是对于for循环的每个迭代(而不是笛卡尔积),我只是得到以下输出。
System.Linq.Enumerable+ConcatNIterator'1[system.int32]
。
这是怎么回事?
解决方法
修改方法以将每个组合作为数组返回:
static IEnumerable<T[]> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences) {
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,(accumulator,sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item }).ToArray());
}
然后将最终的返回值转换为数组数组:
var combArray = CartesianProduct(numList).ToArray();
注意:通常,动态构建时使用List<int>
代替int[]
效率更高,这也取决于您处理答案的方式,IEnumerable<IEnumerable<int>>
可能是更好的形式,或者是IEnumerable<int[]>
而不是数组数组。