C#实现数组列表全排列并生成二维double矩阵
生成数组列表的笛卡尔积并转为二维double数组
需求回顾
给定一个包含多个double数组的列表,需要生成所有可能的元素组合(笛卡尔积),最终输出一个二维double数组,其中行数为所有数组长度的乘积,列数为列表中的数组数量。
比如输入:
List<double[]> myArray = new List<double[]> { new double[] { 1.2, 1.3, 1.4}, new double[] { 2.1, 2.2 }, new double[] { 3.1 } };
预期输出是6×3的二维数组:
{ { 1.2, 2.1, 3.1 }, { 1.2, 2.2, 3.1 }, { 1.3, 2.1, 3.1 }, { 1.3, 2.2, 3.1 }, { 1.4, 2.1, 3.1 }, { 1.4, 2.2, 3.1 } }
现有代码的问题
你提供的递归方法Permutations2返回的是IEnumerable<IEnumerable<double>>,无法直接得到二维数组;且递归实现会产生大量临时对象(比如每次创建List<double>和调用Concat),在数据量较大时效率偏低。
解决方案1:将现有递归结果转为二维数组
如果暂时不想修改递归逻辑,可以通过LINQ将返回的枚举序列直接转为二维数组:
// 调用现有方法并转换 double[][] result = Permutations2(myArray, 0) .Select(combination => combination.ToArray()) .ToArray();
但这种方式依然存在递归带来的效率问题,仅适合小体量数据场景。
解决方案2:高效非递归实现(推荐)
直接通过数组操作生成笛卡尔积,避免递归和不必要的内存开销,效率更高:
public static double[][] GenerateCartesianProduct(List<double[]> arrays) { if (arrays == null || arrays.Count == 0) return Array.Empty<double[]>(); // 计算总组合数:所有数组长度的乘积 int totalCombinations = 1; foreach (var arr in arrays) { totalCombinations *= arr.Length; } int columnCount = arrays.Count; double[][] result = new double[totalCombinations][]; // 初始化每个组合的数组 for (int i = 0; i < totalCombinations; i++) { result[i] = new double[columnCount]; } int repeatTimes = totalCombinations; for (int col = 0; col < columnCount; col++) { var currentArr = arrays[col]; int elementCount = currentArr.Length; repeatTimes /= elementCount; // 按规律填充当前列的所有元素 for (int row = 0; row < totalCombinations; row++) { int elementIndex = (row / repeatTimes) % elementCount; result[row][col] = currentArr[elementIndex]; } } return result; }
代码原理
- 先计算总组合数,提前分配好二维数组的内存;
- 对每一列,计算当前列元素的重复次数,通过数学规律直接定位每个位置应该填充的元素,避免递归调用和临时对象的创建。
使用示例
List<double[]> myArray = new List<double[]> { new double[] { 1.2, 1.3, 1.4}, new double[] { 2.1, 2.2 }, new double[] { 3.1 } }; double[][] product = GenerateCartesianProduct(myArray); // 输出验证 foreach (var combo in product) { Console.WriteLine($"{{ {string.Join(", ", combo)} }}"); }
内容的提问来源于stack exchange,提问作者user129994
相关产品推荐
相关产品推荐

