求动态获取数组下一个唯一组合的方法及代码优化建议
动态获取数组下一个唯一组合的优化建议
问题背景
假设有数组:
let arr = [a, b, c];
该数组的唯一组合为 [a], [b], [c], [a, b], [a, c], [b, c] 和 [a, b, c],对应索引为 [0], [1], [2], [0, 1], [0, 2], [1, 2] 和 [0, 1, 2]。
现需要实现一种动态获取下一个唯一数组组合的方法,输入为当前组合的索引,要求无需先生成所有可能的唯一组合再遍历数组。示例如下:
let a = foo(arr, [1]); // a = [c] 或 [2] let b = foo(arr, [2]); // b = [a, b] 或 [0, 1]
用户实现代码
let arr = ['a', 'b', 'c', 'd', 'e']; let input = [0]; for (let i = 0; i < 31; i++) { input = foo(arr, input); console.log(input.map(index => arr[index])); } function foo(a, b) { let i = b.length - 1; while (i >= 0) { if (b[i] < a.length - (b.length - i)) { b[i]++; break; } i--; } if (i === -1) { b.unshift(0); i++ } if (b.length > a.length) { return [0]; } for (let j = i + 1; j < b.length; j++) { b[j] = b[j - 1] + 1; } return b; }
优化建议
1. 避免修改原输入数组
当前代码直接修改了输入的索引数组b,会导致外部变量被意外修改。建议创建副本操作,消除副作用:
function foo(a, b) { // 复制输入数组,不修改原数据 let current = [...b]; let i = current.length - 1; while (i >= 0) { if (current[i] < a.length - (current.length - i)) { current[i]++; break; } i--; } if (i === -1) { current = [0, ...current]; // 用展开语法替代unshift,逻辑更直观 i++; } if (current.length > a.length) { return [0]; } for (let j = i + 1; j < current.length; j++) { current[j] = current[j - 1] + 1; } return current; }
2. 简化边界判断逻辑
把current.length > a.length的判断提前到扩容操作之后,避免后续不必要的循环执行:
if (i === -1) { current = [0, ...current]; // 提前判断长度是否超标,直接返回初始值 if (current.length > a.length) { return [0]; } i++; }
3. 参数命名语义化
原参数a、b表意模糊,改为更清晰的命名提升代码可读性:
function getNextCombination(sourceArr, currentIndices) { let current = [...currentIndices]; let i = current.length - 1; while (i >= 0) { // 计算当前索引的最大允许值,注释增强可读性 const maxAllowedIndex = sourceArr.length - (current.length - i); if (current[i] < maxAllowedIndex) { current[i]++; break; } i--; } if (i === -1) { current = [0, ...current]; if (current.length > sourceArr.length) { return [0]; } i++; } for (let j = i + 1; j < current.length; j++) { current[j] = current[j - 1] + 1; } return current; }
4. 增加输入合法性校验
添加基础校验,避免非法输入导致逻辑错误:
function getNextCombination(sourceArr, currentIndices) { // 校验输入是否为合法的递增索引组合 const isValidInput = Array.isArray(currentIndices) && currentIndices.every(idx => typeof idx === 'number' && idx >= 0 && idx < sourceArr.length) && currentIndices.every((idx, index) => index === 0 || idx > currentIndices[index - 1]); if (!isValidInput) { throw new Error('输入的索引组合不合法,请传入严格递增的有效索引数组'); } let current = [...currentIndices]; // 后续逻辑... }
5. 简化索引填充逻辑
用Array.from替代内层for循环,让代码更简洁:
// 替换原有的for循环 if (i >= 0) { current = [ ...current.slice(0, i + 1), ...Array.from({ length: current.length - i - 1 }, (_, k) => current[i] + 1 + k) ]; }
内容的提问来源于stack exchange,提问作者argrejer1
相关产品推荐
相关产品推荐

