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

如何以声明式方式识别数组中超出范围值的起止索引区间?

问题描述

我有三个长度为n的数组:

let values = [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5];
let min_arr = [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3];
let max_arr = [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7];
let n = values.length; 

需要找出所有区间的起止索引,这些区间内存在min_arr[i] > values[i]或max_arr[i] < values[i]的情况。

示例中的区间说明:

  • 第一个区间:values[4] = 7 > 6 = max_arr[4],但values[5] = 6未超出范围,因此起止索引为start = 4,end = 5。
  • 第二个区间:values[8]和values[9]都小于对应min_arr的值,但values[10]未超出范围,因此起止索引为start = 8,end = 10。

预期输出:[[4, 5], [8, 10]](注:最后一个结束索引大于n也无妨)

我目前的实现思路是先提取所有超出范围的索引,再合并连续索引生成区间:

// 第一步:获取所有超出范围的索引
let temp = values
  .map((e, i) => min_arr[i] > e || max_arr[i] < e ? i : undefined)
  .filter((e) => e);
console.log(temp);

输出:

[4, 8, 9]
// 第二步:将连续索引转换为区间
let res = [];
let start = temp[0];
for (let i = 0; i < temp.length; i++) {
  if (i + 1 == temp.length) {
    res.push([start, temp[i] + 1]);
    break;
  }
  if (temp[i] + 1 != temp[i + 1]) {
    res.push([start, temp[i] + 1]);
    start = temp[i + 1];
  }
}
console.log(res);

输出:

[[4, 5], [8, 10]]

作为JavaScript新手,我觉得这种方法比较繁琐,想知道如何用声明式方式实现整个过程?


声明式实现方案

可以利用数组的reduce方法完成从判断范围到生成区间的全流程,全程采用声明式风格,逻辑更连贯:

方案一:直接遍历values生成区间

const result = values.reduce((acc, val, idx) => {
  const isOutOfRange = min_arr[idx] > val || max_arr[idx] < val;
  const lastInterval = acc[acc.length - 1];

  if (isOutOfRange) {
    // 当前索引超出范围,且无正在处理的区间时,新建区间
    if (!lastInterval) {
      acc.push([idx, null]);
    }
  } else if (lastInterval && lastInterval[1] === null) {
    // 当前索引未超出范围,但存在未闭合的区间,用当前索引闭合它
    lastInterval[1] = idx;
  }

  return acc;
}, []);

// 处理最后一个未闭合的区间(比如数组末尾连续超出范围的情况)
if (result.length > 0 && result[result.length - 1][1] === null) {
  result[result.length - 1][1] = values.length;
}

console.log(result);

输出:

[[4, 5], [8, 10]]

代码说明

  • 遍历过程中实时判断当前索引是否超出范围,动态维护区间列表;
  • 用null标记未闭合的区间,遇到第一个未超出范围的索引时完成闭合;
  • 遍历结束后处理可能遗留的未闭合区间,避免遗漏。

方案二:先生成标记数组再处理区间

如果需要更清晰的步骤拆分,可以先生成"是否超出范围"的标记数组,再用reduce处理标记生成区间:

// 第一步:生成标记数组,true表示当前索引超出范围
const outOfRangeFlags = values.map((val, idx) => min_arr[idx] > val || max_arr[idx] < val);

// 第二步:基于标记数组生成区间
const result = outOfRangeFlags.reduce((acc, flag, idx) => {
  const lastInterval = acc[acc.length - 1];

  if (flag) {
    // 当前索引超出范围,且无正在处理的区间时,新建区间起始点
    if (!lastInterval) {
      acc.push([idx]);
    }
  } else if (lastInterval && lastInterval.length === 1) {
    // 当前索引未超出范围,闭合之前的区间
    lastInterval.push(idx);
  }

  return acc;
}, []);

// 处理最后一个未闭合的区间
if (result.length > 0 && result[result.length - 1].length === 1) {
  result[result.length - 1].push(values.length);
}

console.log(result);

输出同样符合预期。

内容的提问来源于stack exchange,提问作者rochard4u

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 18:58:04