数组去重合并
最近遇到了一个问题,有一个比较费时的JS操作,在IE下总报错:
通过使用chrome下的profile找出了那个费时的函数,是一个关于数组合并的函数。
1 function union_arr_1(arr, arr_b) { 2 var i, 3 len; 4 5 for (i = 0, len = arr_b.length; i < len; i++) { 6 if (in_arr(arr_b[i], arr)) { 7 continue; 8 } 9 arr.push(arr_b[i]); 10 } 11 12 return arr; 13 } 14 15 function in_arr(num, arr) { 16 var i, 17 len; 18 for (i = 0, len = arr.length; i < len; i++) { 19 if (num == arr[i]) { 20 return true; 21 } 22 } 23 24 return false; 25 }
将两个只含数字的数组进行合并,并且重复的项只保留一个。分析上面的算法,将arr_a与arr_b数组合并,需要遍历数组arr_b,将元素push到arr_a中,在push之前,需要遍历一次arr_a是否包含那个元素,关键影响效率的问题就是这里了。 每插入一个元素前,需要遍历arr_a。
改进的算法:
先将arr_a和arr_b合并,然后再处理重复数据。我们知道object对象是不会包含重复键值对的,因此可以把元素当做属性插入到object中。
1 function union_arr_2(arr, arr_b) { 2 var i, 3 len, 4 arr_c, 5 newArr = [], 6 obj = {}; 7 8 arr_c = arr.concat(arr_b); 9 10 for (i = 0, len = arr_c.length; i < len; i++) { 11 if (!obj[arr_c[i]]) { //查找object对象的属性,要比查找数组更高效 12 obj[arr_c[i]] = 1; 13 newArr.push(arr_c[i]); 14 } 15 } 16 17 return newArr; 18 }
耗时比较:
1 var time_start, 2 i, 3 len, 4 limit_a = 20000, 5 limit_b = 35000, 6 arr_a, 7 arr_b; 8 9 arr_a = []; 10 for(i=0; i<limit_a; i++){ 11 arr_a.push(i); 12 } 13 14 arr_b =[]; 15 for(i=limit_b-limit_a; i<limit_b; i++){ 16 arr_b.push(i); 17 } 18 19 time_start = new Date(); 20 union_arr_1(arr_a, arr_b); 21 console.log("First method takes " + ((new Date())-time_start) + 'ms.'); 22 23 arr_a = []; 24 for(i=0; i<limit_a; i++){ 25 arr_a.push(i); 26 } 27 28 arr_b =[]; 29 for(i=limit_b-limit_a; i<limit_b; i++){ 30 arr_b.push(i); 31 } 32 33 time_start = new Date(); 34 union_arr_2(arr_a, arr_b); 35 console.log("First method takes " + ((new Date())-time_start) + 'ms.');
随着合并数组数据量的增加,性能相差将会非常大。
First method takes 864ms.
First method takes 17ms.