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

基于子对象数组过滤分组父对象数组:现有JS代码的性能疑问与简洁化优化请求

代码性能优化与简洁性改进求助

我已经写完下面这段JavaScript代码,也能得到预期的输出结果,但总觉得代码写得不够整洁。想请教大家两个问题:

  1. 这段代码有没有性能消耗过大的问题?
  2. 能不能在完全不改变输出结果的前提下,把代码优化得更简洁易懂?

(注:StackOverflow要求补充更多细节,但我认为仅通过代码运行结果即可理解问题,故补充此说明)

原代码

const verses = [{ index: 1, verses: [{ level: 1 }, { level: 1 } ] }, { index: 2, verses: [{ level: 1 }, { level: 1 } ] }, { index: 3, verses: [{ level: 2 }] }, { index: 4, verses: [{ level: 2 }] }, { index: 5, verses: [{ level: 2 }, { level: 2 } ] }, { index: 6, verses: [{ level: 3 }, { level: 3 } ] }, { index: 7, verses: [{ level: 3 }, { level: 3 }, { level: 4 }, { level: 4 } ] } ]
function getVerseIndexByLevel(level) {
  const result = verses.map(v => {
    const mappingByLevel = Math.max.apply(Math, [...new Set(v.verses.map(w => w.level))])
    const mappingByVerse = v.index
    return { level: mappingByLevel, verse: mappingByVerse }
  }).filter(v => v.level === level).map(v => v.verse)
  return result
}
for (let i = 1; i <= 4; i++) {
  console.log({ level: i, verse: getVerseIndexByLevel(i) })
}

先说说性能问题

原代码确实存在不必要的性能消耗:

  • 每次调用getVerseIndexByLevel都会完整遍历一遍verses数组,你循环调用了4次,等于把整个数组重复遍历了4次
  • 每个verse项里,还要做v.verses.map(w => w.level)生成新数组、转Set去重、再展开成数组求最大值,这些操作在每次函数调用时都会重复执行,数据量越大,冗余消耗越明显
  • 额外提一句:原代码里的去重操作其实是多余的——求最大值时重复的level值完全不影响结果,这一步白白增加了计算量

优化后的代码(输出完全一致)

我们可以先预处理一次数据,把每个verse的最高level和对应的index提前映射好,后续查询直接取值即可,这样只需要遍历一次原数组,性能提升明显,代码也更简洁:

const verses = [{ index: 1, verses: [{ level: 1 }, { level: 1 } ] }, { index: 2, verses: [{ level: 1 }, { level: 1 } ] }, { index: 3, verses: [{ level: 2 }] }, { index: 4, verses: [{ level: 2 }] }, { index: 5, verses: [{ level: 2 }, { level: 2 } ] }, { index: 6, verses: [{ level: 3 }, { level: 3 } ] }, { index: 7, verses: [{ level: 3 }, { level: 3 }, { level: 4 }, { level: 4 } ] } ]

// 预处理:生成level到对应verse索引数组的映射
const levelToVerses = verses.reduce((map, verseItem) => {
  // 直接取当前verse里的最大level,无需去重
  const maxLevel = Math.max(...verseItem.verses.map(item => item.level));
  // 初始化对应level的数组(如果不存在的话)
  if (!map[maxLevel]) map[maxLevel] = [];
  map[maxLevel].push(verseItem.index);
  return map;
}, {});

// 简化查询函数,逻辑一目了然
function getVerseIndexByLevel(level) {
  // 不存在对应level时返回空数组,和原代码行为完全一致
  return levelToVerses[level] || [];
}

// 原循环逻辑保持不变
for (let i = 1; i <= 4; i++) {
  console.log({ level: i, verse: getVerseIndexByLevel(i) })
}

优化点说明

  1. 性能大幅提升:只遍历一次verses数组完成预处理,后续查询都是O(1)的直接取值操作,彻底避免了重复的数组遍历、map、去重等冗余计算
  2. 代码更简洁易懂:
    • 用reduce做映射逻辑清晰,一步完成数据预处理
    • 去掉了原代码中多余的去重操作,减少不必要的计算
    • 查询函数简化到极致,一眼就能看出它的功能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 18:42:45