如何实现含一维数组的输入数组的全路径组合展开?
问题描述
我需要实现一个功能:将包含单个元素或一维数组的输入数组展开,生成所有到叶子“节点”的路径组合,暂时不清楚这个操作的特定名称。以下是规则和示例:
功能规则与示例
输入数组的元素只能是单个值或一维数组,展开规则为:每次遇到数组时,将现有所有路径拆分为与该数组元素数量一致的路径,每个拆分后的路径分别追加该数组的一个元素。
示例:
let input = [1, 2, [3, 4], [5, 6]];
处理过程:
- 先处理单个元素,当前结果为
[[1, 2]] - 处理数组
[3,4]:将现有路径拆分,分别追加3和4,得到[[1,2,3], [1,2,4]] - 处理数组
[5,6]:将每个现有路径拆分,分别追加5和6,最终结果:
[[1, 2, 3, 5], [1, 2, 4, 5], [1, 2, 3, 6], [1, 2, 4, 6]]
遇到的问题
我尝试从后往前构建结果(用pop方法),但代码无法正常运行,也处理不了以下特殊情况:
input1 = [1, 2, 3](无嵌套数组,预期输出[[1,2,3]])input2 = [](空输入,预期输出[[]])
我的代码如下:
function flatPath(input, result = [[]]) { while (input.length) { const last = input.pop(); if (Array.isArray(last)) { result = flatPath(last, [...result, ...result]); } else { for (let ar of result) { result.push(last); } } } return result; } let result = flatPath([1, 2, [3, 4], [2, 5, 6] ]); console.log(result);
用TypeScript编译时还会报错:
Parameter 'input' implicitly has an 'any' type.
Argument of type 'any' is not assignable to parameter of type 'never'.
请问我的代码有什么问题?有没有更规范的实现方式?
问题分析与解决
原代码的问题
- 逻辑错误:
- 处理单个元素时,直接往
result数组里push(last),但result是路径数组的集合,正确操作应该是给每个路径数组追加元素,而非往集合里加单个值,这会导致路径结构完全混乱。 - 处理嵌套数组时,仅把
result复制两份传入递归,这只适配数组长度为2的场景,遇到长度为3及以上的数组(比如[2,5,6])时,无法生成对应数量的路径。 - 使用
pop()会直接修改原输入数组,产生不必要的副作用,也会导致原数组被清空。
- 处理单个元素时,直接往
- TypeScript类型问题:
- 未给
input和result指定明确类型,导致TS无法推断类型,出现隐式any错误;递归调用时类型不匹配,触发never类型报错。
- 未给
正确的实现方式
JavaScript版本
采用从前往后遍历的方式,逐个处理输入元素,避免修改原数组:
- 初始结果设为
[[]](空路径) - 遍历每个元素:
- 若为单个值,给所有现有路径追加该值
- 若为数组,将每个现有路径复制多份,每份分别追加数组中的一个元素
function flatPath(input) { let result = [[]]; for (const item of input) { if (Array.isArray(item)) { const temp = []; for (const path of result) { for (const val of item) { temp.push([...path, val]); } } result = temp; } else { result = result.map(path => [...path, item]); } } return result; } // 测试用例 console.log(flatPath([1, 2, [3, 4], [5, 6]])); // 输出: [[1,2,3,5],[1,2,4,5],[1,2,3,6],[1,2,4,6]] console.log(flatPath([1,2,3])); // 输出: [[1,2,3]] console.log(flatPath([])); // 输出: [[]]
TypeScript版本
给函数指定泛型类型,明确输入输出的类型结构,通过TS类型检查:
function flatPath<T>(input: (T | T[])[]): T[][] { let result: T[][] = [[]]; for (const item of input) { if (Array.isArray(item)) { const temp: T[][] = []; for (const path of result) { for (const val of item) { temp.push([...path, val]); } } result = temp; } else { result = result.map(path => [...path, item]); } } return result; } // 测试用例 console.log(flatPath([1, 2, [3, 4], [5, 6]])); console.log(flatPath([1,2,3])); console.log(flatPath([]));
额外说明
这个操作本质是笛卡尔积的变体:每个数组元素相当于一个集合,单个元素相当于仅含一个元素的集合,最终的路径就是这些集合的笛卡尔积。
内容的提问来源于stack exchange,提问作者Lorah Attkins
相关产品推荐
相关产品推荐

