双层循环
双层循环,使用额外数组
var arr = [1, 6, 4, 6, 6, 4, 2, "a", "a"];
var res = [];
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < res.length; j++) {
if (arr[i] === res[j]) {
break;
}
}
//如果这两个数相等说明循环完了,没有相等的元素
if (j == res.length) {
res.push(arr[i]);
}
}
console.log(res); //[1, 6, 4, 2, "a"]
双层循环,利用splice
双指针遍历,splice操作会改变原始数组,注意下标
for(i = 0;i<arr.length-1;i++){
for(j = i+1;j<arr.length;){
if(arr[i] === arr[j]){
arr.splice(j,1)
}else{
j++;
}
}
}
排序
此方法有局限,sort后的数组形如[1,'1',1]会无法完全去重
利用sort,单层for循环
arr.sort((a,b)=>{
return a-b;
})
for(let i = 0;i <arr.length-1;i++){
if(arr[i]===arr[i+1]){
arr.splice(i+1,1)
i--; //注意
}
}
// 使用额外数组
var newArr = [];
arr = arr.sort();
for (let i = 0; i < arr.length; i++) {
if (arr[i] !== arr[i+1]) {
newArr.push(arr[i])
}
}
// 不同写法
// for (let i = 1; i < arr.length; i++) {
// arr[i] !== arr[i-1] && newArr.push(arr[i])
//}
console.log(newArr);
sort排序+filter
var array = [1, 2, 1, 1, '1'];
function unique(array) {
// array.concat()生成array的副本,sort排序不改变array原数组;使用concat为浅拷贝
return array.concat().sort().filter(function(item, index, array){
// 如果是第一个元素或者相邻的元素不相同
return !index || item !== array[index - 1]
})
}
console.log(unique(array)); // [1, '1', 2]
利用 for/forEach/filter()和 indexOf()
indexOf 底层还是使用 === 进行判断, NaN === NaN的结果为 false,所以使用 indexOf 查找不到 NaN 元素
var arr = [1, 2, NaN];
arr.indexOf(NaN); // -1
for+indexOf
var res = [];
for (var i = 0; i < arr.length; i++) {
if (res.indexOf(arr[i]) == -1) {
res.push(arr[i]);
}
}
console.log(res);
forEach+indexOf
var res = [];
arr.forEach(function(item, index) {
if (res.indexOf(item) == -1) {
res.push(item);
}
});
console.log(res);
filter+indexOf
var res = arr.filter(function(item, index) {
return arr.indexOf(item) == index;
});
console.log(res);
ES6 的 new Set()实现去重
var arr = [1, 6, 4, 6, 6, 4, 2, "a", "a"];
//第一种
var newarr = Array.from(new Set(arr));
console.log(newarr); //[1, 6, 4, 2, "a"]
//第二种
var newarr1 = [...new Set(arr)];
console.log(newarr1); //[1, 6, 4, 2, "a"]
set可以对NaN去重
function unique(array) {
return Array.from(new Set(array));
}
console.log(unique([NaN, NaN])) // [NaN]
ES6 的 includes 实现去重
var arr = [1, 6, 4, 6, 6, 4, 2, "a", "a"];
var res = [];
arr.forEach(function(item, index) {
if (!res.includes(item)) {
res.push(item);
}
});
console.log(res); //[1, 6, 4, 2, "a"]
利用对象的属性去重
根据对象的属性不能相同的特点进行去重
var arr = [1, 1, '1', '1', true, true,'true', 'true', 15, 15, false, false, undefined, undefined, null, null, 'NaN', NaN, NaN,0, 0, 'a', 'a', {}, {}]
var res = [];
var obj = {};
for (var i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) { //对象没找到该属性返回undefined
obj[arr[i]] = true;
res.push(arr[i]);
}
}
console.log(res); // 此方法 1 和 '1'会判断为同一个值,因为对象的键值只能是字符串
// [1, true, 15, false, undefined, null, 'NaN', 0, 'a', {…}]
利用hasOwnProperty
对象的键值只能是字符串,1和'1'会判断为同一个值。可以使用 typeof item + item 拼成字符串作为 key 值来避免这个问题。
function unique(arr) {
var obj = {};
return arr.filter(function(item, index, arr){
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}] 全部去重了
但依然无法正确区分出两个对象,如 {value: 1} 和 {value: 2},因为 typeof item + item 的结果都会是 object[object Object],可以使用 JSON.stringify 将对象序列化:
var array = [{value: 1}, {value: 1}, {value: 2}];
function unique(array) {
var obj = {};
return array.filter(function(item, index, array){
console.log(typeof item + JSON.stringify(item))
return obj.hasOwnProperty(typeof item + JSON.stringify(item)) ? false : (obj[typeof item + JSON.stringify(item)] = true)
})
}
console.log(unique(array)); // [{value: 1}, {value: 2}]
但以上方法仍无法处理正则对象去重, JSON.stringify 任何一个正则表达式的结果都是 {}
如/a/和/b/会被判断为同一值,解决方法:判断是正则的情况
item = item instanceof RegExp ? item.toString() : item
var array = [/a/, /a/, /b/, "1", 1, new String('1'), 1, new String('1'), NaN, NaN, null, undefined];
function unique(array) {
var obj = {};
return array.filter(function(item, index, array){
item = item instanceof RegExp ? item.toString() : item;
return obj.hasOwnProperty(typeof item + JSON.stringify(item)) ? false : (obj[typeof item + JSON.stringify(item)] = true)
})
}
console.log(unique(array))
// [/a/, /b/, '1', 1, String, NaN, null, undefined]
利用map实现去重
let map = new Map()
let newArr = []
arr.forEach(ele => {
if (!map.has(ele)) {
map.set(ele, 1)
newArr.push(ele)
}
});
map+filter
function unique (arr) {
const map = new Map()
return arr.filter((a) => !map.has(a) && map.set(a, 1))
}
利用reduce实现去重
let res = (arr) =>{
let newArr = []
arr.reduce((pre, next)=>{
if(!pre.get(next)){
pre.set(next, 1)
newArr.push(next)
}
return pre
},new Map())
return newArr.sort((a, b) => {
return a - b
})
}
console.log(res(arr))
利用reduce+includes
function unique(arr){
return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr));
// [1, 'true', true, 15, false, undefined, null, NaN, 'NaN', 0, 'a', {…}, {…}]
// {}未去重
for...of + includes() 合并去重
function distinct(a, b) {
let arr = a.concat(b)
let result = []
for (let i of arr) {
!result.includes(i) && result.push(i)
}
return result
}
利用递归
var arr = [3, 4, 5, 2, 3, 1, 1, 2];
function unique(arr){
var newArr = arr;
//先排序
newArr.sort((a,b) => {
return a - b;
});
function loop(index){
if (index >= 1) {
if (newArr[index] === newArr[index-1]) {
newArr.splice(index,1);//有相等的 则删除后一个
}
loop(index-1);//递归
}
}
loop(newArr.length-1);
return newArr
}
console.log(unique(arr));
注意
NaN、undefined、null及{}、正则等对象的去重需要特别处理
NaN==NaN为false / NaN===NaN为false
{} 和 正则对象 使用==和===也都为false
console.log(null == null); // true console.log(null === null); // true console.log(undefined == undefined); // true console.log(undefined === undefined); // true console.log(null == undefined); // true console.log(null === undefined); // false
var str1 = '1'; var str2 = new String('1'); console.log(str1 == str2); // true console.log(str1 === str2); // false
对于数组
var array = [1, 1, '1', '1', null, null, undefined, undefined, new String('1'), new String('1'), /a/, /a/, NaN, NaN];
各方法的去重情况: