方法⼀:利用ES6 Set去重 ( ES6中最常用)
1.普通数组
特点: Set
是一种数据结构,它只允许存储唯一的值,因此可以轻松实现数组去重。
const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueArr = Array.from(new Set(arr));
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
详细说明:
Set
本身不能包含重复值,当数组传入Set
时,重复的元素会自动被过滤掉。- 然后使用
Array.from()
或[...Set]
将Set
转换回数组。
2.特殊数组
特点:
Set
认为NaN
是相等的,所以会移除重复的NaN
。undefined
也可以正常去重。- 对于数组和对象元素,
Set
会按引用去重,只有引用相同的对象或数组才会被认为是相同的。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
const uniqueArr = [...new Set(arr)];
console.log(uniqueArr); // 输出: [NaN, undefined, [1], [1], {a: 1}, {a: 1}]
结果:
NaN
和undefined
被去重。- 引用不同的数组
[1]
和对象{a: 1}
没有被去重。
方法二:利用for嵌套for,然后splice去重 ( ES5中最常用)
1.普通数组
特点: 这是一个传统的方法,通过双重循环遍历数组,并使用 splice
方法移除重复元素。
const arr = [1, 2, 3, 3, 4, 5, 5];
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
j--; // 由于数组长度减少,索引需要调整
}
}
}
console.log(arr); // 输出: [1, 2, 3, 4, 5]
详细说明:
- 外层循环遍历数组中的每个元素,内层循环将该元素与其后面的所有元素进行比较。
- 如果发现重复的元素,则用
splice
方法移除它。
2.特殊数组
特点:
- 直接比较元素的值,所以
NaN
不会被认为是相等的,无法去重。 undefined
可以去重。- 对于数组和对象元素,比较的是引用地址,无法去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(arr); // 输出: [NaN, NaN, undefined, [1], [1], {a: 1}, {a: 1}]
结果:
NaN
未被去重,因为NaN === NaN
为false
。undefined
被去重。- 数组和对象未被去重。
方法三:利用indexOf去重
1.普通数组
特点: indexOf
方法返回数组中某个指定元素首次出现的位置,利用这一点可以实现去重。
const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
if (uniqueArr.indexOf(arr[i]) === -1) {
uniqueArr.push(arr[i]);
}
}
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
详细说明:
indexOf
会返回元素在数组中第一次出现的索引,如果返回-1
表示该元素还未在uniqueArr
中存在。- 如果元素不存在于
uniqueArr
中,则将其推入uniqueArr
。
2.特殊数组
特点:
indexOf
对NaN
无法正确判断,不能去重。undefined
可以去重。- 数组和对象无法去重,因为
indexOf
也是基于引用比较。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(uniqueArr); // 输出: [NaN, NaN, undefined, [1], [1], {a: 1}, {a: 1}]
结果:
NaN
未被去重。undefined
被去重。- 数组和对象未被去重。
方法四:利用sort()
1.普通数组
特点: 通过对数组进行排序,然后遍历数组,相邻元素比较是否相同来去重。
const arr = [1, 2, 3, 3, 4, 5, 5];
arr.sort();
const uniqueArr = [arr[0]];
for (let i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i - 1]) {
uniqueArr.push(arr[i]);
}
}
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
详细说明:
- 先使用
sort()
对数组进行排序,使得相同元素相邻。 - 然后从第二个元素开始,依次与前一个元素比较,不相同则加入
uniqueArr
。
2.特殊数组
特点:
sort()
排序不能正确处理NaN
,但可以通过比较去重。undefined
可以去重。- 数组和对象按引用比较,无法去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(uniqueArr); // 输出: [NaN, NaN, undefined, [1], [1], {a: 1}, {a: 1}]
结果:
NaN
未被去重。undefined
被去重。- 数组和对象未被去重。
方法五:利用对象的属性不能相同的特点进行去重
1.普通数组
特点: 对象的属性名是唯一的,可以利用这一点来去重。
const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueObj = {};
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
if (!uniqueObj[arr[i]]) {
uniqueObj[arr[i]] = true;
uniqueArr.push(arr[i]);
}
}
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
详细说明:
- 遍历数组时,利用元素的值作为对象的键,如果对象中不存在该键,则添加它并推入
uniqueArr
。 - 这种方法适用于基本类型的数组,不适用于复杂类型(如对象数组)。
2.特殊数组
特点:
NaN
和undefined
都可以被正确去重。- 数组和对象无法去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
const uniqueObj = {};
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
const key = typeof arr[i] + JSON.stringify(arr[i]);
if (!uniqueObj[key]) {
uniqueObj[key] = true;
uniqueArr.push(arr[i]);
}
}
console.log(uniqueArr); // 输出: [NaN, undefined, [1], [1], {a: 1}, {a: 1}]
结果:
NaN
和undefined
被去重。- 数组和对象未被去重。
方法六:利用includes
1.普通数组
特点: includes
方法用于判断一个数组是否包含某个指定的值。
const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
if (!uniqueArr.includes(arr[i])) {
uniqueArr.push(arr[i]);
}
}
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
详细说明:
includes
返回布尔值,如果数组中不存在该元素,则push
到uniqueArr
。
2.特殊数组
特点:
includes
不能正确判断NaN
,因此无法去重。undefined
可以去重。- 数组和对象无法去重,因为
includes
也是基于引用比较。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(uniqueArr); // 输出: [NaN, NaN, undefined, [1], [1], {a: 1}, {a: 1}]
结果:
NaN
未被去重。undefined
被去重。- 数组和对象未被去重。
方法七:利用hasOwnProperty
1.普通数组
特点: 类似于方法五,使用对象的属性名作为唯一标识进行去重。
const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueObj = {};
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
if (!uniqueObj.hasOwnProperty(arr[i])) {
uniqueObj[arr[i]] = true;
uniqueArr.push(arr[i]);
}
}
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
详细说明:
hasOwnProperty
用于检查对象是否包含特定属性,这样可以避免属性被undefined
覆盖。
2.特殊数组
特点:
NaN
和undefined
可以被去重。- 数组和对象无法去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
const uniqueObj = {};
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
const key = typeof arr[i] + JSON.stringify(arr[i]);
if (!uniqueObj.hasOwnProperty(key)) {
uniqueObj[key] = true;
uniqueArr.push(arr[i]);
}
}
console.log(uniqueArr); // 输出: [NaN, undefined, [1], [1], {a: 1}, {a: 1}]
结果:
NaN
和undefined
被去重。- 数组和对象未被去重。
方法八:利用递归去重
1.普通数组
特点: 通过递归函数进行去重,可以处理嵌套数组或多层嵌套的情况。
const arr = [1, 2, 3, 3, 4, 5, 5];
function unique(arr) {
if (arr.length === 0) return [];
const [first, ...rest] = arr;
return rest.includes(first) ? unique(rest) : [first, ...unique(rest)];
}
console.log(unique(arr)); // 输出: [1, 2, 3, 4, 5]
详细说明:
- 递归将数组拆分为头部和尾部,然后检查头部是否在尾部存在,如果存在则递归处理尾部数组。
2.特殊数组
特点:
NaN
不能去重。undefined
可以去重。- 数组和对象的引用不同,无法去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(unique(arr)); // 输出: [NaN, NaN, undefined, [1], [1], {a: 1}, {a: 1}]
结果:
NaN
未被去重。undefined
被去重。- 数组和对象未被去重。
方法九:利用Map数据结构去重
1.普通数组
特点: Map
对象允许键值对,并且键是唯一的,利用这一特性可以去重。
const arr = [1, 2, 3, 3, 4, 5, 5];
const map = new Map();
const uniqueArr = arr.filter(item => !map.has(item) && map.set(item, 1));
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
详细说明:
- 通过
filter
遍历数组,同时检查Map
是否已有该值,没有则添加到Map
并保留该元素。
2.特殊数组
特点:
NaN
和undefined
都可以被去重。- 数组和对象可以通过引用来去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(uniqueArr); // 输出: [NaN, undefined, [1], [1], {a: 1}, {a: 1}]
结果:
NaN
和undefined
被去重。- 数组和对象未被去重。
方法十:利用reduce+includes
1.普通数组
特点: reduce
可以累积操作结果,通过 includes
检查是否已存在该元素。
const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueArr = arr.reduce((acc, curr) => {
if (!acc.includes(curr)) acc.push(curr);
return acc;
}, []);
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
详细说明:
reduce
会遍历数组并累积结果,如果当前元素不在累积数组中,则添加进去。
2.特殊数组
特点:
NaN
不能去重。undefined
可以去重。- 数组和对象无法去重,因为
includes
也是基于引用比较。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(uniqueArr); // 输出: [NaN, NaN, undefined, , [1], [1], {a: 1}, {a: 1}]
方法十一:利用filter
1.普通数组
特点: filter
的主要作用是通过一个回调函数,过滤掉不符合条件的数组元素。通过结合 indexOf
、includes
、map
或者其他逻辑判断,可以实现数组去重。
const arr = [1, 2, 2, 3, 4, 4, 5, 'a', 'b', 'a'];
const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index);
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5, 'a', 'b']
详细说明:
arr.indexOf(item)
会返回数组中第一次出现该元素的索引。- 如果当前元素的索引与
indexOf
返回的索引相同,说明该元素是第一次出现,保留它。 - 如果不同,则该元素是重复的,过滤掉。
2.特殊数组
特点:
NaN
是一个特殊的值,NaN !== NaN
,所以indexOf
和includes
无法正确识别NaN
。undefined
可以通过indexOf
或includes
进行正常识别,因为undefined === undefined
是true
。- 数组属于引用类型,
indexOf
和includes
对于数组只进行引用比较,而不是值比较。 - 对象也是引用类型,同样,
indexOf
和includes
对对象进行引用比较,而不是值比较。
去重方法:
const arr = [NaN, 1, NaN, 2, 2];
const uniqueArr = arr.filter((item, index) => {
return item !== item ? arr.findIndex(isNaN) === index : arr.indexOf(item) === index;
});
console.log(uniqueArr); // 输出: [NaN, 1, 2]
说明:
- 使用
item !== item
来判断是否为NaN
,因为只有NaN !== NaN
为true
。 - 对于
NaN
,利用findIndex(isNaN)
查找第一个NaN
的索引。
去重方法:
const arr = [undefined, 1, undefined, 2, 2];
const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index);
console.log(uniqueArr); // 输出: [undefined, 1, 2]
说明:
undefined
的去重处理与普通基本类型数据(如数字、字符串等)相同。
去重方法:
const arr = [[1, 2], [1, 2], [3, 4], {a: 1}, {a: 1}, {b: 2}];
const uniqueArr = arr.filter((item, index) => {
return arr.findIndex(i => JSON.stringify(i) === JSON.stringify(item)) === index;
});
console.log(uniqueArr); // 输出: [[1, 2], [3, 4], {a: 1}, {b: 2}]
说明:
- 通过
JSON.stringify
将数组序列化为字符串进行比较,从而实现值比较去重。 findIndex
返回第一个与当前序列化后的字符串相同的索引,来判断是否保留该数组元素。- 该方法可以识别对象属性和值是否相同,从而实现对象去重。