方案1 . 创建一个空数组 , 循环验证 + 数组方法
思路:
循环原有数组中的每一项 , 每拿到一项都往新数组中添加 .
添加之前验证新数组中是否存在这一项 ,不存在再增加 .
let ary = [1,2,3,1,2,1,2,3,2,1,2,3]
let newAry = [];
for (let i = 0; i < ary.length; i++) {
// 循环获取原有数组中的每一项
let item = ary[i];
// 验证新数组中是否存在这一项
if(newAry.includes(item)){
// 存在这一项,不再增加到新数组中,继续下一轮循环即可
continue;
}
// 新数组中不存在这一项, 我们将其加入到新数组即可
newAry.push(item);
}
console.log(newAry); // => [1,2,3]
优化 : 使用函数式编程 forEach
缺点 : 不兼容 IE6-8
let ary = [1,2,3,1,2,1,2,3,2,1,2,3]
let newAry = [];
ary.forEach(item =>{
if(newAry.includes(item)) return;
newAry.push(item);
});
console.log(newAry); // => [1,2,3]
方案2 . 不创建空数组 , 循环比较 + 数组方法 双for循环 数组塌陷
思路
先分别拿出数组中的每一项A,用这一项和 "它后面的每项"依次进行比较 如果遇到和当前项A相同的,则在原来数组中把这一项移除掉
循环重复上述过程
不用 let , includes , indexOf , forEach 保证兼容性
var ary = [1,2,3,1,2,1,2,3,2,1,2,3]
for (var i = 0; i < ary.length; i++) {
// item : 每一次循环拿出来的当前项
// i : 当前项索引 i + 1 : 代表后一项
var item = ary[i];
// 让当前项和后面的每一项进行比较 (循环)
for(var j = i + 1; j < ary.length; j++){
// compare : 分别从 item 后面拿出来要比较的每一项
var compare = ary[j]
// 如果 compare 和 item 相等, 说明这一项是重复的, 我们把compare删掉
if(compare === item){
// j 索引这一项要从数组中移除
ary.splice(j,1)
}
}
}
console.log(ary); // => [1,2,3,2]
上述结果并不是我们想要的, 仍旧有重复项未剔除
数组塌陷问题
var ary = [10,20,30];
for (var i = 0; i < ary.length; i++) {
// 把当前项从数组中移除 => 原来数组会变
ary.splice(i,1)
}
解决: 数组塌陷后,为了不让i提前一位后跳加,我们先把i-- ,然后再继续
var ary = [1,2,3,1,2,1,2,3,2,1,2,3]
for (var i = 0; i < ary.length; i++) {
// item : 每一次循环拿出来的当前项
// i : 当前项索引 i + 1 : 代表后一项
var item = ary[i];
// 让当前项和后面的每一项进行比较 (循环)
for(var j = i + 1; j < ary.length; j++){
// compare : 分别从 item 后面拿出来要比较的每一项
var compare = ary[j]
// 如果 compare 和 item 相等, 说明这一项是重复的, 我们把compare删掉
if(compare === item){
// j 索引这一项要从数组中移除
ary.splice(j,1)
// 数组塌陷了: j后面的每一项索引都提前了一位, 下次要比较的应该还是j这个索引的内容,不能跳过.
j--;
}
}
}
console.log(ary); // => [1,2,3]
过程注释版:
var ary = [1,2,3,1,2,1,2,3,2,1,2,3]
for (var i = 0; i < ary.length; i++) {
// 第一轮
// i = 0 item = 1 拿到第一项
// 第二轮
// i = 1 item = 2 ...
var item = ary[i];
for(var j = i + 1; j < ary.length; j++){
// j =1 compore =2 2!==1
// j =2 compore =3 3!==1
// j =3 compore =1 1===1 ary.splice(3,1) [1,2,3,(1)2,...]
// j =4 把2就漏掉了 没有进行比较 所以 j-- j++
// j =3 compore =2 ...
var compare = ary[j];
if(compare === item){
ary.splice(j,1);
j--;
}
}
}
console.log(ary); // => [1,2,3]
方案3 . 创建空对象 , 循环比较 + 数组方法
思路
创建一个空对象
循环数组中的每一项,把拿到的项当做对象的属性名和属性值存储起来
存储之前需要判断 如果 存储的项 和新对象里 同属性名的 属性值 相同,则重复
没有这一项,则新对象里同属性名的属性值是undefined,不相等,这一项不存在,放进去
对于重复项,用splice删除 并解决数组塌陷问题
var ary = [1,2,3,1,2,1,2,3,2,1,2,3];
//1.创建一个空对象
let obj = {};
// 2. 循环数组中的每一项,把每一项向对象中进行存储 => item : item
for(let i = 0;i < ary.length;i++){
let item = ary[i];
// 3. 每一次存储之前进行判断 : 验证obj中是否存在这一项
if(obj[item] !== undefined){
// 说明此项已经存在 ,删除该项并解决数组塌陷问题 图1-1 然后继续循环
ary.splice(i,1);
i--;
continue;
}
// 想把当前item变量存储的值给obj 所以不能用obj.item <=> obj['item']
obj[item] = item;
}
console.log(ary); //=> [1,2,3]
图 1-1
性能: 方案1的includes每次都要检索全部数组,性能较差 ; 方案2 双重循环,性能也不如方案3 .
但是 , 基于 splice 实现删除性能不好 : 当前项被删除后 , 后面每一项的索引都要向前提一位 ,如果后面内容过多 , 一定影响性能 .
性能优化思路: 把最后一项的值替换当前要删除的项,然后删除最后一项(已经被提前,不需要了重复了).同时,被替换的这个位置未参与过比较,所以还得需要参与一次比较才完整.
性能优化图解:
性能优化后的代码
var ary = [1,2,3,1,2,1,2,3,2,1,2,3];
let obj = {};
for(let i = 0;i < ary.length;i++){
let item = ary[i];
if(obj[item] !== undefined){
// 替换
ary[i]=ary[ary.length-1];
// 删除最后一项
ary.length--;
// 不让i累加保证比较的完整性
i--;
continue;
}
obj[item] = item;
}
console.log(ary); //=> [1,2,3]
封装成函数
/*
* unique : 实现数组去重的方法
*
* @params
* ary [Array] 要去重的数组
* @return
* [Array] 去重后的数组
* by Ark on 20190724
*
*/
function unique(ary){
let obj = {};
for(let i = 0;i < ary.length;i++){
let item = ary[i];
if(obj[item] !== undefined){
ary[i]=ary[ary.length-1];
ary.length--;
i--;
continue;
}
obj[item] = item;
}
return ary;
}
方案4 . 正则
目前看看就好
let ary = [12,23,12,15,25,23,25,14,16];
ary.sort((a,b)=> a - b );
let str = ary.join('@') + '@';
console.log(str); //=> 12@12@14@15@16@23@23@25@25@
let reg =/(\d+@)\1*/g // \1* 即表示与前一项一模一样的项又出现0到多次
console.log(str.match(reg)); //=> (6) ['12@12@', '14@', '15@', '16@', '23@23@', '25@25@']
let newAry = [];
str.replace(reg, (n,m) =>{
// 捕获适配的每一项
console.log('n:'+n);
console.log('m:'+m);
m = Number(m.slice(0,m.length-1));
newAry.push(m);
});
console.log(newAry); //=> (6) [12, 14, 15, 16, 23, 25]
基于ES6的 Set( 对应的 Map ) 实现去重
let ary = [12,23,12,15,25,23,25,14,16];
ary = [...new Set(ary)];
console.log(ary); //=> (6) [12, 14, 15, 16, 23, 25]