高效生成分类JSON数组:三种实现方案的效率对比问询
哪种方法生成目标JSON的效率最高?
针对你描述的场景(用户选择项数量在1-100之间),方法C的效率是最高的——它通过增量更新维护JSON结构,避免了每次操作都全量遍历DOM或重建整个数据结构的冗余开销。下面我来逐个分析三种方法的优劣,再给出方法C的具体实现思路:
方法A:点击按钮时批量处理
这种方法的核心是只在用户点击exec按钮时才开始处理数据:先把DOM中的选择项转成扁平的临时数组,再按类别分组。
缺点:
- 冗余操作:每次点击按钮都要遍历全部选择项(最多100次),先转临时数组再分组,相当于两次全量遍历;
- 临时数组额外占用内存,虽然100项的内存可以忽略,但属于没必要的开销;
- 如果用户频繁点击按钮,重复处理的成本会累积。
方法B:每次选择后全量重建JSON
这种方法每次用户选择/取消选择项时,都重新遍历整个user_selection_list来构建data_json。
缺点:
- 重复劳动:比如用户选了100次,每次都要遍历最多100个DOM元素,总遍历次数是100*100=10000次——虽然100项的量级下不会卡顿,但完全是没必要的重复工作;
- DOM遍历本身比内存中操作数据要慢,每次全量遍历DOM都会带来额外的性能开销。
方法C:增量更新JSON结构(最优解)
这种方法的核心是只针对当前操作的项来更新data_json,而不是每次都全量重建:
- 当用户添加项时:检查
data_json中是否存在对应类别,不存在则新建类别并添加item;存在则直接把item加入对应类别的列表; - 当用户移除项时:找到对应类别,删除item;如果类别下没有item了,就删掉整个类别对象。
为什么高效?
- 每次操作只需要处理当前项,最多遍历一次
data_json的类别数组(类别数量远小于100,比如示例里只有A/B/C三个),时间复杂度极低; - 点击
exec按钮时直接用已经维护好的data_json,不需要任何额外处理; - 避免了重复遍历DOM或全量重建数据结构的冗余开销。
具体实现示例(原生JS)
// 初始化目标JSON数组 let data_json = []; // 先同步初始的user_selection_list到data_json document.querySelectorAll('.user_selection_list li').forEach(li => { const category = li.dataset.category; const item = li.dataset.item; updateDataJson(category, item, true); }); // 处理full_list中项的点击事件(添加/移除到选择列表) function handleItemClick(e) { const targetLi = e.target.closest('li'); if (!targetLi) return; const category = targetLi.dataset.category; const item = targetLi.dataset.item; const selectionList = document.querySelector('.user_selection_list'); const existingLi = selectionList.querySelector(`li[data-category="${category}"][data-item="${item}"]`); if (existingLi) { // 移除已选项 selectionList.removeChild(existingLi); updateDataJson(category, item, false); } else { // 添加新选项 const newLi = targetLi.cloneNode(true); selectionList.appendChild(newLi); updateDataJson(category, item, true); } } // 核心:增量更新data_json的函数 function updateDataJson(category, item, isAdd) { const categoryObj = data_json.find(obj => obj.category === category); if (isAdd) { if (!categoryObj) { // 类别不存在,新建类别对象 data_json.push({ category, items: [item] }); } else if (!categoryObj.items.includes(item)) { // 类别存在,item未添加,加入列表 categoryObj.items.push(item); } } else { if (categoryObj) { // 移除item categoryObj.items = categoryObj.items.filter(i => i !== item); // 如果类别下已无item,删除该类别 if (categoryObj.items.length === 0) { data_json = data_json.filter(obj => obj.category !== category); } } } } // exec按钮点击事件:直接使用已维护好的data_json function execute() { console.log('最终JSON:', data_json); // 这里可以把data_json用于后续逻辑,比如提交接口等 } // 绑定full_list的点击事件 document.querySelector('.full_list').addEventListener('click', handleItemClick);
优化版本(用对象存储类别,查找更快)
如果你的类别数量较多(比如超过10个),可以把data_json改成以类别为key的对象,这样查找类别的时间复杂度是O(1),效率更高:
// 改用对象存储,类别查找更快 let data_map = {}; function updateDataMap(category, item, isAdd) { if (isAdd) { if (!data_map[category]) data_map[category] = []; if (!data_map[category].includes(item)) data_map[category].push(item); } else { if (data_map[category]) { data_map[category] = data_map[category].filter(i => i !== item); if (data_map[category].length === 0) delete data_map[category]; } } } // exec按钮点击时转成需要的数组格式 function execute() { const data_json = Object.entries(data_map).map(([category, items]) => ({ category, items })); console.log('最终JSON:', data_json); }
总结:在1-100项的选择场景下,方法C的增量更新方式不仅效率最高,而且代码逻辑更清晰,避免了不必要的重复操作。
内容的提问来源于stack exchange,提问作者Rezzy
相关产品推荐
相关产品推荐

