如何使用AngularJS函数简化for循环实现数组去重合并
AngularJS 下的列表去重合并实现方案
原代码中内层循环的break仅会终止对ListB的遍历,不会影响外层ListA的循环执行。出现遍历中断的核心原因是代码最后推入ListB的是未定义的newObj,运行时抛出引用错误终止了脚本执行,和break逻辑无关。
AngularJS 提供了内置迭代工具方法,可以更简洁地实现「将ListA中不存在于ListB的项追加到ListB」的需求,下面给出两种可直接使用的实现:
1. 语义直观的基础实现(适合小数据量场景)
直接用AngularJS内置的angular.forEach做迭代,配合数组原生的some方法做存在性判断(AngularJS兼容的所有浏览器环境均支持该方法),逻辑和原有思路一致,但写法更简洁,也不会出现变量引用错误:
angular.forEach($scope.ListA, function(item) { const isExist = $scope.ListB.some(function(obj) { return obj.Name === item.Name && obj.Field === item.Field && obj.DisplayName === item.DisplayName; }); if (!isExist) { $scope.ListB.push(item); } });
原有代码里找到匹配项后
break的优化思路是合理的,Array.prototype.some本身在找到第一个匹配项后就会终止遍历,和手动写break的效果完全一致,不需要额外定义found标记位。
2. 高性能实现(适合千条以上数据的大列表场景)
双重循环的时间复杂度是O(n*m),列表数据量大的时候性能损耗明显,可以先为ListB建立哈希索引,把整体时间复杂度降到O(n+m):
const existIndex = {}; // 先遍历ListB建立已存在项的索引 angular.forEach($scope.ListB, function(obj) { // 用三个字段拼接成唯一key,分隔符选字段值里不会出现的特殊字符即可 const key = [obj.Name, obj.Field, obj.DisplayName].join('##_##'); existIndex[key] = true; }); // 遍历ListA做增量插入 angular.forEach($scope.ListA, function(item) { const key = [item.Name, item.Field, item.DisplayName].join('##_##'); if (!existIndex[key]) { $scope.ListB.push(item); // 新插入的项同步加入索引,避免ListA内部有重复项时重复插入 existIndex[key] = true; } });
注意事项
- 如果三个匹配字段的值可能包含你选用的分隔符,可以直接用
angular.toJson([obj.Name, obj.Field, obj.DisplayName])生成唯一key,只是性能比字符串拼接稍差。 - 如果不需要兼容IE8及更早版本,也可以直接用ES6的
for...of循环配合Set做查重,逻辑会更简洁,AngularJS本身不会对原生JS语法做限制。
内容的提问来源于stack exchange,提问作者Georgia
相关产品推荐
相关产品推荐

