如何用JavaScript的filter替代reduce实现分组?性能孰优?
用Filter实现合并相同Key的数组对象?性能对比分析
一、用Filter实现的写法
Filter本身是用来筛选元素的,要实现合并得搭配其他方法。先拿到所有不重复的stage,再逐个用Filter筛出对应元素,最后提取content:
const data = [{ "stage": "AT_CALLCENTER", "content": "Hello", }, { "stage": "AT_CALLCENTER", "content": "Bye", }, { "stage": "AT_SITE", "content": "Good", }, { "stage": "AT_SITE", "content": "Morning", } ]; // 先获取所有唯一的stage值 const uniqueStages = [...new Set(data.map(item => item.stage))]; // 遍历每个stage,用filter筛选对应元素并提取content const result = {}; uniqueStages.forEach(stage => { result[stage] = data.filter(item => item.stage === stage).map(item => item.content); }); console.log(result);
二、Filter根本不是更优选择
你朋友说Filter性能更好是错的,核心原因是:
- 遍历次数差太多:Reduce的实现只需要遍历数组1次(时间复杂度O(n));而Filter的方式,每遇到一个新的stage,就要把整个数组再遍历一遍(时间复杂度O(n*m),m是不同stage的数量)。数据量越大,这种重复遍历的性能损耗越夸张。
- 另外你原来的Reduce代码其实还有优化空间——每次用
...展开对象和数组会创建新的引用,没必要。改成直接操作累加器对象,性能会更上一层楼:
// 优化后的Reduce写法,避免不必要的展开操作 const optimizedResult = data.reduce((acc, item) => { // 如果当前stage还没在累加器里,先初始化空数组 if (!acc[item.stage]) { acc[item.stage] = []; } // 直接往数组里push内容,不用创建新数组 acc[item.stage].push(item.content); return acc; }, {});
这个优化版的Reduce,不仅时间复杂度还是O(n),内存开销也更小,处理大量数据时比Filter的写法快得多,也比你原来的Reduce代码高效。
三、总结
- Filter能实现需求,但性能拉胯,尤其是数据量大的时候,完全不如Reduce。
- 最优方案是用优化后的Reduce写法,既简洁又高效,适合生产环境处理大量数据的场景。
内容的提问来源于stack exchange,提问作者Jakub
相关产品推荐
相关产品推荐

