如何仅用一次循环为数组添加唯一id 无需两次循环实现
单次遍历实现嵌套数组扁平化+全局唯一自增ID的方案
核心思路:在遍历逻辑外维护全局自增计数器,或者利用结果数组的长度做天然计数,即可在一次遍历内完成嵌套元素收集+ID赋值,完全规避分组下标重复的问题。
固定两层嵌套结构(大部分GraphQL返回的常见场景)
如果你的返回结构固定是外层数组的每个元素下挂载items子数组,直接用嵌套forEach配合外部计数器即可,总遍历次数等于所有item的总数量,无额外开销:
// 示例原始数据,可根据你的实际返回结构调整字段名 const rawData = [ { category: '1', items: [{ title: 'item1' }, { title: 'item2' }] }, { category: '2', items: [{ title: 'item3' }, { title: 'item4' }, { title: 'item5' }] } ] const res = [] let autoId = 0 rawData.forEach(group => { group.items.forEach(item => { res.push({ ...item, id: autoId++ }) }) })
任意深度嵌套结构
如果存在不确定层级的嵌套items,可以用递归配合计数器实现,同样是单次遍历:
const res = [] let autoId = 0 function flatten (data) { data.forEach(node => { // 匹配带items的节点,可根据你的实际结构调整判断条件 if (Array.isArray(node.items)) { node.items.forEach(item => { res.push({ ...item, id: autoId++ }) // 递归处理子元素的嵌套items flatten([item]) }) } }) } flatten(rawData)
纯函数式实现(无外部变量)
如果不想引入外部计数器,可以用reduce结合结果数组的天然长度做自增ID,逻辑更简洁:
const res = rawData.reduce((acc, group) => { return acc.concat( group.items.map(item => ({ ...item, id: acc.length // 已存入的元素长度正好是下一个ID的取值 })) ) }, [])
以上所有方案的时间复杂度均为O(n),n为所有待提取item的总数量,全程只有一次遍历逻辑,没有额外的二次遍历开销。
内容的提问来源于stack exchange,提问作者GʀᴜᴍᴘʏCᴀᴛ
相关产品推荐
相关产品推荐

