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

如何优雅高效地按索引区间将一维数组分割为多维数组?

问题:根据指定索引区间分割一维数组为二维数组

给定存储需移除元素索引区间的二维数组trim,需要找到一种优雅且高性能的方法,根据这些区间将一维数组words分割为目标二维数组。示例如下:

// 传入的trim参数
var trim = [
  [3, 4], // 移除索引3、4的两个元素
  [9, 10] // 移除索引9、10的两个元素
];

var words = [
  { word: "hello", st: 0 },
  { word: "stack-overflow", st: 0.5 },
  { word: "lets", st: 1 },
  { word: "remove", st: 1.5 },
  { word: "some", st: 2 },
  { word: "words", st: 2.5 },
  { word: "efficiently", st: 3 },
  { word: "lets", st: 3.5 },
  { word: "do", st: 4 },
  { word: "it", st: 4.5 },
  { word: "yay", st: 5 }
];

// 期望得到的结果
var result = [
  [
    { word: "hello", st: 0 },
    { word: "stack-overflow", st: 0.5 },
    { word: "lets", st: 1 }
  ],
  [
    { word: "words", st: 2.5 },
    { word: "efficiently", st: 3 },
    { word: "lets", st: 3.5 },
    { word: "do", st: 4 }
  ]
];

我目前用reduce实现的代码只能过滤掉指定区间的元素,无法生成目标二维数组:

words.reduce((acc, curr, i) => {
    const wordBetween = trim.some(t => {
        return t[0] <= i && t[1] >= i
    });

    console.log({wordBetween, curr})

    if (wordBetween) {
        return acc;
    }
    
    return [...acc, curr]
}, [])

解决方案

方法一:高效切片法(推荐,性能更优)

通过计算所有需要保留的区间,利用数组原生slice方法批量提取元素,适合大数据量场景:

function splitByTrimIntervals(words, trim) {
  if (trim.length === 0) return [words];
  
  // 先对trim区间按起始索引排序,避免乱序导致错误
  const sortedTrim = [...trim].sort((a, b) => a[0] - b[0]);
  const result = [];
  let currentStart = 0;

  for (const [trimStart, trimEnd] of sortedTrim) {
    // 提取当前保留段:从currentStart到trimStart的前一位
    if (currentStart < trimStart) {
      result.push(words.slice(currentStart, trimStart));
    }
    // 更新起始位置为移除区间的下一位
    currentStart = trimEnd + 1;
    // 如果起始位置超出数组长度,提前终止循环
    if (currentStart >= words.length) break;
  }

  // 处理最后一段未被覆盖的元素
  if (currentStart < words.length) {
    result.push(words.slice(currentStart));
  }

  return result;
}

// 调用测试
console.log(splitByTrimIntervals(words, trim));

方法二:遍历跟踪法(逻辑直观)

通过遍历数组,实时跟踪当前收集的子数组,遇到移除区间时完成分割:

function splitByTrimIntervals(words, trim) {
  const sortedTrim = [...trim].sort((a, b) => a[0] - b[0]);
  const result = [];
  let currentSegment = [];
  let trimIndex = 0;
  let currentTrim = sortedTrim[trimIndex];

  for (let i = 0; i < words.length; i++) {
    // 检查当前索引是否在移除区间内
    if (currentTrim && i >= currentTrim[0] && i <= currentTrim[1]) {
      // 如果当前子数组有元素,存入结果并清空
      if (currentSegment.length > 0) {
        result.push(currentSegment);
        currentSegment = [];
      }
      // 到达移除区间末尾时,切换到下一个移除区间
      if (i === currentTrim[1]) {
        trimIndex++;
        currentTrim = sortedTrim[trimIndex];
      }
    } else {
      // 不在移除区间,加入当前子数组
      currentSegment.push(words[i]);
    }
  }

  // 遍历结束后,把最后一段非空子数组存入结果
  if (currentSegment.length > 0) {
    result.push(currentSegment);
  }

  return result;
}

// 调用测试
console.log(splitByTrimIntervals(words, trim));

核心思路说明

两种方法都先对trim区间排序,确保处理顺序正确。区别在于:

  • 切片法通过计算保留区间的起始和结束位置,批量提取元素,原生slice方法性能更高
  • 遍历法逐元素处理,逻辑更直观,适合需要对元素做额外处理的场景

你的原reduce代码只实现了元素过滤,没有处理分割逻辑。上述方法通过跟踪分割时机(遇到移除区间时),将之前收集的元素作为独立子数组存入结果,从而得到目标二维数组。


内容的提问来源于stack exchange,提问作者Michael Joseph Aubry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 11:35:39