数组去重的7种算法

参考《javascript种难点实例精讲》

1. 遍历数组

算法1的主要思想是在函数内部新建一个数组,对传入的数组进行遍历。如果遍历的值不在新数组中就添加进去,如果已经存在就不做处理。

function arrayUnique(array) {
   var result = [];
   for (var i = 0; i < array.length; i++) {
       if(result.indexOf(array[i]) === -1) {
           result.push(array[i]);
       }
   }
   return result;
}
var array = [1, 4, 5, 7, 4, 8, 1, 10, 4];
console.log(arrayUnique(array));

以上代码在运行后得到的结果为“[1, 4, 5, 7, 8, 10]”。

2. 利用对象键值对

算法2的主要思想是新建一个JS对象以及一个新的数组,对传入的数组进行遍历,判断当前遍历的值是否为JS对象的键。如果是,表示该元素已出现过,则不做处理;如果不是,表示该元素第一次出现,则给该JS对象插入该键,同时插入新的数组,最终返回新的数组。

function arrayUnique2(array) {
   var obj = {}, result = [], val, type;
   for (var i = 0; i < array.length; i++) {
       val = array[i];
       if (!obj[val]) {
           obj[val] = 'yes';
           result.push(val);
       }
   }
   return result;
}
var array = [1, 4, 5, 7, 4, 8, 1, 10, 4];
console.log(arrayUnique2(array));

上面的代码存在些许缺陷,即不能判断Number类型和String类型的数字。因为不管是Number类型的1,还是String类型的"1",作为对象的key都会被当作先插入类型的1处理。所以会把Number类型和String类型相等的数字作为相等的值来处理,但实际上它们并非是重复的值。
对于数组[1, 4, 5, 7, 4, 8, 1, 10, 4, '1']的处理结果为“[1, 4, 5, 7, 8, 10]”,这显然是不合理的,正确结果应为“[1, 4, 5, 7, 8, 10, '1']”。
为了解决这个问题,我们需要将数据类型作为key的value值。这个value值为一个数组,判断key的类型是否在数组中,如果在,则代表元素重复,否则不重复,并将数据类型push到value中去。
根据以上分析,得到以下代码,其中obj为键值对象,result为最终返回结果

function arrayUnique2(array) {
   var obj = {}, result = [], val, type;
   for (var i = 0; i < array.length; i++) {
       val = array[i];
       type = typeof val;
       if (!obj[val]) {
           obj[val] = [type];
           result.push(val);
       } else if (obj[val].indexOf(type) < 0) {   // 判断数据类型是否存在 
           obj[val].push(type);
           result.push(val);
       }
   }
   return result;
}
var array2 = [1, 4, 5, 7, 4, 8, 1, 10, 4, '1'];
console.log(arrayUnique2(array2));

以上的代码运行后得到的结果为“[1, 4, 5, 7, 8, 10, '1']”,可以发现1与'1'不为重复的元素,满足实际情况。

3. 先排序,再去重

算法3的主要思想是借助原生的sort()函数对数组进行排序,然后对排序后

的数组进行相邻元素的去重,将去重后的元素添加至新的数组中,返回这个新数组。
根据以上分析,得到以下代码

function arrayUnique3(array) {
   var result = [array[0]];
   array.sort(function(a,b){return a-b});
   for (var i = 0; i < array.length; i++) {
       if (array[i] !== result[result.length - 1]) {
           result.push(array[i]);
       }
   }
   return result;
}
var array3 = [1, 4, 5, 7, 4, 8, 1, 10, 4];
console.log(arrayUnique3(array3));

以上代码的运行结果为“[1, 4, 5, 7, 8, 10]”。

4. 优先遍历数组
算法4的主要思想是利用双层循环,分别指定循环的索引i与j,j的初始值为i+1。在每层循环中,比较索引i和j的值是否相等,如果相等则表示数组中出现了相同的值,则需要更新索引i与j,操作为++i;同时将其赋值给j,再对新的索引i与j的值进行比较。循环结束后会得到一个索引值i,表示的是右侧没有出现相同的值,将其push到结果数组中,最后返回结果数组。
根据以上的分析,得到以下的代码

function arrayUnique4(array) {
   var result = [];
   for (var i = 0, l = array.length; i < array.length; i++) {
       for (var j = i + 1; j < l; j++) {
            // 依次与后面的值进行比较,如果出现相同的值,则更改索引值
            if (array[i] === array[j]) {
                j = ++i;
            }
       }
       // 每轮比较完毕后,索引为i的值为数组中只出现一次的值
       result.push(array[i]);
   }
   return result;
 }
var array4 = [1, 4, 5, 7, 4, 8, 1, 10, 4];
console.log(arrayUnique4(array4));

以上代码的运行结果为“[1, 4, 5, 7, 8, 10]”。

5. 基于reduce()函数
算法5的主要思想是利用reduce()函数,类似于算法2,需要借助一个key-value对象。在reduce()函数的循环中判断key是否重复,如果为是,则将当前元素push至结果数组中。实际做法是设置initialValue为一个空数组[],同时将initialValue作为最终的结果进行返回。在reduce()函数的每一轮循环中都会判断数据类型,如果数据类型不同,将表示为不同的值,如1和"1",将作为不重复的值。
根据以上的分析,得到以下的代码

function arrayUnique5(array) {
   var obj = {}, type;
   return array.reduce(function (preValue, curValue) {
       type = typeof curValue;
       if (!obj[curValue]) {
           obj[curValue] = [type];
           preValue.push(curValue);
       } else if (obj[curValue].indexOf(type) < 0) {   // 判断数据类型是否存在
            obj[curValue].push(type);
           preValue.push(curValue);
       }
       return preValue;
   }, []);
}
var array5 = [1, 4, 5, 7, 4, 8, 1, 10, 4, '1'];
console.log(arrayUnique5(array4));

以上代码的运行结果为“[1, 4, 5, 7, 8, 10, "1"]”

6. 借助ES6的Set数据结构

算法6的主要思想是借助于ES6中新增的Set数据结构,它类似于数组,但是有一个特点,即成员都是唯一的,所以Set具有自动去重的功能。
在ES6中,Array类型增加了一个from()函数,用于将类数组对象转化为数组,然后再结合Set可以完美实现数组的去重。
根据以上的分析,得到以下的代码。

function arrayUnique6(array) {
   return Array.from(new Set(array));
}
var arr6 = [1, 4, 5, 7, 4, 8, 1, 10, 4, '1'];
console.log(arrayUnique6(arr6));

以上代码的运行结果为“[1, 4, 5, 7, 8, 10, "1"]”。

7. 借助ES6的Map数据结构

算法7的主要思想是借助于ES6中新增的Map数据结构,它是一种基于key-value存储数据的结构,每个key都只对应唯一的value。如果将数组元素作为Map的key,那么判断Map中是否有相同的key,就可以判断出元素的重复性。
Map还有一个特点是key会识别不同数据类型的数据,即1与"1"在Map中会作为不同的key处理,不需要通过额外的函数来判断数据类型。
基于Map数据结构,通过filter()函数过滤,即可获得去重后的结果。
根据以上的分析,得到以下的代码。

function arrayUnique7(array) {
   var map = new Map();
   return array.filter((item) => !map.has(item) && map.set(item, 1));
}
var arr7 = [1, 4, 5, 7, 4, 8, 1, 10, 4, '1'];
console.log(arrayUnique7(arr7));

以上代码的运行结果为“[1, 4, 5, 7, 8, 10, "1"]”。

posted @ 2021-07-21 09:41  鸡腿太小  阅读(865)  评论(0编辑  收藏  举报