如何使用LINQ函数生成两个Enumerable按索引选元素的所有组合序列?
如何用LINQ生成两个数组对应索引元素的所有组合序列
这是个典型的笛卡尔积生成问题——每个索引位置有两个可选元素,我们需要把所有位置的选项交叉组合,最终得到2^n种序列(n是数组长度)。用LINQ可以很优雅地实现,我给你两种实用的方案:
方案一:用Aggregate逐步累积组合
这个方法的核心是从空序列开始,逐个索引扩展出所有可能的组合:
// 定义输入数组 var arr1 = new[] { 1, 2, 3 }; var arr2 = new[] { -1, -2, -3 }; // 生成所有组合序列 var allCombinations = Enumerable.Range(0, arr1.Length) .Aggregate( // 初始值:包含一个空列表的集合,作为组合的起点 new List<List<int>> { new List<int>() }, (currentCombos, currentIndex) => currentCombos // 对每个已有的组合,分别拼接当前索引的两个可选元素 .SelectMany(combo => new[] { arr1[currentIndex], arr2[currentIndex] } .Select(num => new List<int>(combo) { num }) ) .ToList() ); // 打印验证结果 foreach (var sequence in allCombinations) { Console.WriteLine(string.Join(", ", sequence)); }
代码解释:
Enumerable.Range(0, arr1.Length):遍历数组的每个索引(这里默认两个数组长度一致,若需要兼容不同长度可加判断)Aggregate:相当于一个“累积器”,从空序列开始,每次迭代都把现有组合和当前索引的两个元素拼接,生成新的组合集合SelectMany:把每个组合生成的两个新序列扁平化成一个大集合,避免嵌套结构
方案二:自定义笛卡尔积扩展方法
如果需要更通用的笛卡尔积能力,可以先写一个扩展方法,再应用到每个索引的选项上:
// 通用笛卡尔积扩展方法 public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences) { IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() }; foreach (var sequence in sequences) { result = result.SelectMany(seq => sequence, (seq, item) => seq.Concat(new[] { item })); } return result; } // 使用示例 var arr1 = new[] { 1, 2, 3 }; var arr2 = new[] { -1, -2, -3 }; // 先把每个索引的两个元素包装成一个序列集合 var indexOptions = Enumerable.Range(0, arr1.Length) .Select(i => new[] { arr1[i], arr2[i] }); // 调用笛卡尔积方法生成所有组合 var allCombinations = indexOptions.CartesianProduct().ToList(); // 输出结果 foreach (var sequence in allCombinations) { Console.WriteLine(string.Join(", ", sequence)); }
这个方案的优势:
- 扩展方法
CartesianProduct可以复用在其他需要生成笛卡尔积的场景 - 逻辑更清晰:先准备好每个位置的可选元素集合,再一次性生成所有组合
两种方案最终都会输出你预期的8种序列:
1, 2, 3;-1, 2, 3;1, -2, 3;1, 2, -3;-1, -2, 3;-1, 2, -3;1, -2, -3;-1, -2, -3
内容的提问来源于stack exchange,提问作者user13693463
相关产品推荐
相关产品推荐

