一、测试模板
写了一个测试模板,用来计算它们的耗时,测试环境是在谷歌浏览器。
// 先生成一个长度足够长的数组
let arr1 = Array.from(Array(100000), (item, index) => index);
let arr2 = Array.from(Array(50000), (item, index) => index * 2);
let arr = [...arr1, ...arr2];
// 方法所用时长
console.log(`去重前数组的长度: ${arr.length}`);
let startTime = +new Date();
// unique方法返回去重后的数组
let result = unique(arr);
let endtTime = +new Date();
console.log(`去重后数组的长度: ${result.length}`);
console.log(`耗时:${endtTime - startTime}毫秒`);
// 测试方法
function unique(arr){
if (!Array.isArray(arr)) {
console.log('arr 不是数组');
return;
}
return unique1(arr); // 具体方法
}
二、测试方法
1、双重for循环
这个是最容易理解的方法,外层循环遍历元素,内层循环检查是否重复。
定义一个数组res
保存结果,遍历需要去重的数组,如果该元素已经存在在res
中,则说明是重复的元素;如果没有,则放入 res
中。
function unique1(arr){
var res = [];
var isRepeat;
for (let ai = 1, alen = arr.length; ai < alen; ai++) {
isRepeat = false;
for (let ri = 0, rlen = res.length; ri < rlen; ri++) {
if (res[ri] == arr[ai]) {
isRepeat = true;
break;
}
}
if (!isRepeat) res.push(arr[ai]);
}
return res;
}
// 输出
// 去重前数组的长度: 150000
// 去重后数组的长度: 100000
// 耗时:3967毫秒
// 重复试验输出:3954、3990、3942、3975、3964
这个方法处理一个15w长度的数组要4秒左右。这个写法是将原数组中的元素和结果数组中的元素一一作比较。
下面这个写法是比较两个原数组,然后将重复元素的最后一个元素放入结果数组中。
function unique1(arr) {
var res = [];
var alen = arr.length;
for (let ai = 1; ai < alen; ai++) {
for (let ri = ai + 1; ri < alen; ri++){
if (arr[ai] === arr[ri]) ri = ++ai;
}
res.push(arr[ai]);
}
return res;
}
// 耗时:9314、9232、9122、9220、9175
但是这个写法处理15W长度的数组耗时是九千多毫秒。原因是第一个写法是将原数组arr
和结果数组res
比较,第二个写法是将两个原数组自己作比较(这个时间复杂度没得说,就是O(nm)
)。结果数组res
一开始的长度是0,和原数组比较相当于一个巨人背着一个小小孩走路,虽然这个小小孩会慢慢长大,但总是比巨人要小很多,自然会走快些。第二个写法是原数组跟原数组比较,相当于一个巨人背着另一个同样重的巨人走路,这样自然也走不快。
所以用双重for
循环比较时,不要比较两个原数组,要将原数组和结果数组比较。
2、循环方法 + indexOf()
在实验循环方法:for
循环、for...of
、filter()
、map()
、forEach()
、reduce()
等方法分别搭配indexOf()
时,得到的结果都相差不大,结构也都差不多,都是一次循环加indexOf()
。 所以便将它们归为一类。
1、for循环 + indexOf()
function unique2(arr){
var res = arr.length > 0 ? [arr[0]] : [];
for (let ai = 1, alen = arr.length; ai < alen; ai++) {
if (res.indexOf(arr[ai]) === -1) res.push(arr[ai]);
}
return res;
}
// 耗时:7761、7735、7845、7775、7828
2、for...of + indexOf()
function unique2(arr) {
var res = [];
for (let item of arr) {
if (res.indexOf(item) === -1) res.push(item);
}
return res;
}
// 耗时:7805、7771、7835、7841、7787
3、filter() + indexOf()
function unique2(arr) {
var res = arr.filter((item, index)=> {
return arr.indexOf(item) === index;
})
return res;
}
// 耗时:7833、7809、7820、7749、7778
4、map() + indexOf()
function unique2(arr) {
var res = arr.map((item, index)=> {
return arr.indexOf(item) === index;
})
return res;
}
// 耗时:7773、7842、7884、7815、7763、7855
5、forEach() + indexOf()
function unique2(arr) {
var res = [];
arr.forEach((item, index, array) => {
if (res.indexOf(item) == -1) res.push(item);
})
return res;
}
// 耗时:7805、7789、7737、7771、7780
6、循环方法 + includes()
也可以是循环方法搭配includes()
使用,includes()
方法是用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false。includes()
和indexOf()
类似,耗时也都差不多。
function unique2(arr) {
var res = [];
for (let item of arr) {
if (res.includes(item) === false) res.push(item);
}
return res;
}
// 耗时:7785、7869、7925、7872、7972
3、sort()排序后遍历数组
先使用 sort()对数组进行排序,然后比较相邻元素是否相等,从而排除重复项
function unique3(arr) {
arr = arr.sort();
var res = arr.length > 0 ? [arr[0]] : [];
for (let ai = 1, alen = arr.length; ai < alen; ai++) {
if (arr[ai] !== arr[ai-1]) res.push(arr[ai]);
}
return res;
}
// 耗时:13、13、14、13、12
4、new Set()
ES6
新增了Set
这一数据结构,类似于数组,Set
的成员具有唯一性,基于这一特性,就非常适合用来做数组去重。
function unique4(arr) {
return Array.from(new Set(arr)); // 耗时:14、13、11、10、11
// return [...new Set(arr)]; // 耗时:15、14、11、10、10
}
关于Set
的使用,还可以有两种搭配,一个是Array.from()
,一个是...(展开运算符)
,耗时都差不多。那一种都可以。
5、new Map()
ES6
新增的还有Map()
,这种方法和Set()
类似,也是具有唯一性。
function unique5(arr) {
var res = [];
var myMap = new Map();
for (var ai = 0, alen = arr.length; ai < alen; ai++) {
if(!myMap.has(arr[ai])){
myMap.set(arr[ai], 1);
res.push(arr[ai]);
}
}
return res;
}
// 耗时: 19、21、20、18、21
6、Object唯一属性
利用对象的属性不会重复这一特性,校验数组元素是否重复。
function unique6(arr){
var obj = {};
var res = [];
for (let item of arr) {
if (!obj[item]) {
res.push(item);
obj[item] = 1;
}
}
return res;
}
// 耗时: 11、17、15、10、10
这种法子也是可以的嘛,但是因为对象的Key
是字符串,还是有一些限制的。