# 数组去重
# 双重循环
let arr = [1, 2, 1, 4, 'a', 'b', 'b'];
function unique(arr) {
let res = [];
let i;
let j;
for (i = 0; i < arr.length; i++) {
for (j = 0; j < res.length; j++) {
if (res[j] === arr[i]) {
break;
}
}
if (j === res.length) {
res.push(arr[i]);
}
}
return res;
}
console.log(unique(arr));
# 循环 + indexOf
let arr = [1, 2, 1, 4, 'a', 'b', 'b'];
function unique(arr) {
let res = [];
for (let i = 0; i < arr.length; i++) {
if (res.indexOf(arr[i]) === -1) {
res.push(arr[i]);
}
}
return res;
}
console.log(unique(arr));
# 排序 + 去重
let arr = [1, 2, 1, 4, 'a', 'b', 'b'];
function unique(arr) {
let res = [];
// 注意,sort排序并不总是正确的
let sortArr = arr.sort();
for (let i = 0; i < sortArr.length; i++) {
if (i === 0 || sortArr[i] !== sortArr[i - 1]) {
res.push(sortArr[i]);
}
}
return res;
}
console.log(unique(arr));
# 封装 unique 函数
结合前面的方法,增加一个 isSorted 参数判断参数 arr 是否已排序
let arr = [1, 2, 1, 4, 'a', 'b', 'b'];
function unique(arr, isSorted) {
let res = [];
for (let i = 0; i < arr.length; i++) {
if (isSorted) {
if (i === 0 || arr[i] !== arr[i - 1]) {
res.push(arr[i]);
}
} else {
if (res.indexOf(arr[i]) === -1) {
res.push(arr[i]);
}
}
}
return res;
}
console.log(unique(arr));
# 增强 unique 函数
- 新增功能:不区分大小写的去重。
- 思路:增加一个自定义处理函数 processFn,对大小写进行处理
- tip:之所以将 processFn 作为参数传入而不是写在 unique 函数内,是因为 processFn 还可以对每个元素进行任意处理,而不仅仅是区分大小写。
let arr = [1, 2, 'B', 'a', 'A', 'b'];
function unique(arr, isSorted, processFn) {
let res = [];
let temp = [];
for (let i = 0; i < arr.length; i++) {
// 根据是否区分大小写来处理当前的值
const computed = processFn ? processFn(arr[i]) : arr[i];
if (isSorted) {
if (i === 0 || computed !== temp) {
res.push(arr[i]);
temp = computed;
}
} else if (processFn) {
// 没排序,大小写不敏感
// 使用temp来保存处理成不区分大小写后的所有元素
if (temp.indexOf(computed) === -1) {
temp.push(computed);
res.push(arr[i]);
}
} else {
// 没排序且大小写敏感
if (res.indexOf(arr[i]) === -1) {
res.push(arr[i]);
}
}
}
return res;
}
console.log(
unique(arr, false, item => {
return typeof item === 'string' ? item.toLowerCase() : item;
})
);
# filter
let arr = [1, 2, 1, 4, 'a', 'b', 'b'];
function unique(arr) {
return arr.filter((item, index, list) => {
return list.indexOf(item) === index;
});
}
console.log(unique(arr));
排序后去重
let arr = [1, 2, 1, 4, 'a', 'b', 'b'];
function unique(arr) {
// 注意,sort排序并不总是正确的
return arr
.concat()
.sort()
.filter((item, index, list) => {
return !index || item !== list[index - 1];
});
}
console.log(unique(arr));
# map 结构(object)
let arr = [1, 2, 1, 4, '1', 'b', 'b', { name: 'foo' }, { name: 'foo' }, { name: 'baz' }];
function unique(arr) {
// 也可以使用 new Map() 和 new WeakMap()
// Map的键除了string可以是其他任意类型的值
// WeakMap的键只能是对象(null除外),且键的引用是弱引用,不参与垃圾回收
let map = {};
let res = [];
for (let i = 0; i < arr.length; i++) {
// 区分 1 和 ”1“,使用类型+值的字符串作为key
// let key = typeof arr[i] + arr[i]
// typeof arr[i] + arr[i] 不能处理对象,比如:
// typeof { name: 'foo' } + { name: 'foo' } -> "object" + { name: 'foo' }.toString() -> "object[object Object]"
// typeof { name: 'bar' } + { name: 'bar' } -> "object" + { name: 'bar' }.toString() -> "object[object Object]"
// 另外对象的形式一致认为相同,比如 { name: 'foo' } 等于 { name: 'foo' },否则所有对象都不全等
// 因此使用 JSON.stringify(arr[i])
let key = typeof arr[i] + JSON.stringify(arr[i]);
// 排除原型链上的同名属性
if (!map.hasOwnProperty(key)) {
map[key] = true;
res.push(arr[i]);
}
}
return res;
}
console.log(unique(arr));
# ES6 的 Set
let arr = [1, 2, 1, 4, 'a', 'b', 'b'];
function unique(arr) {
// return [...new Set(arr)]
return Array.from(new Set(arr));
}
console.log(unique(arr));