You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求动态获取数组下一个唯一组合的方法及代码优化建议

动态获取数组下一个唯一组合的优化建议

问题背景

假设有数组:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 18:05:32