在进行项目开发的时候,有时候需要把一些前端的数组进行去重处理,得到一个去重后的数据,然后再进行相关的操作,这也是在前端面试中经常出现的问题

数组去重的多种方法:

  1. 利用 ES6 Set 去重
  2. 利用 for 嵌套 for,然后 splice 去重
  3. 利用 indexOf 去重
  4. 利用 sort() 去重
  5. 利用对象的属性不能相同的特点进行去重
  6. 利用 includes 去重
  7. 利用 hasOwnProperty 去重
  8. 利用 filter 去重
  9. 利用递归去重
  10. 利用 Map 数据结构去重
  11. 利用 reduce+includes 去重
  12. […new Set(arr)] 去重

数组去重利用 ES6 Set 去重数组

Set 自带的特性,数据不重复

Array.from() 方法将 Set 对象转换为数组,并返回该数组作为去重后的新数组。

时间复杂度为 O(n),因为 Set 对象只需要遍历一次原数组即可完成去重操作

注:无法判断{}重复的情况

const _deleteRepeat = array => {    return Array.from(new Set(array))}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log("去重后:=>",_deleteRepeat(arr));//去重后:=> [ 1, 15, "abc", true, false, undefined, null, NaN, {}, {} ]

利用 for 嵌套 for,然后 splice 去重

双层循环,外层循环元素, 内层循环时比较值。值相同时,则删去这个值。(比较相邻两个数如果重复用 splice 删除)

时间复杂度为 O(n^2),因为两层循环需要对所有元素进行比较。因此,这种方法在处理大型数组时可能会导致性能问题。⚠️

注:无法判断NaN{} 重复的情况

const _deleteRepeat = array => {    for (let i = 0; i < array.length; i++) {        for (let j = i + 1; j < array.length; j++) {            if (array[i] === array[j]) {                array.splice(j, 1);                j --;            }        }    }}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];_deleteRepeat(arr)console.log(arr)// [ 1, 15, "abc", true, false, undefined, null, NaN, NaN, {}, {}]

利用 indexOf 去重

新建⼀个空的结果数组, for 循环原数组, 判断结果数组是否存在当前元素, 如果有相同的值则跳过,不相同则 push 进数组

时间复杂度为 O(n^2),因为 indexOf() 方法需要对所有元素进行比较。因此,这种方法在处理大型数组时可能会导致性能问题。⚠️

注:无法判断NaN{} 重复的情况

const _deleteRepeat = array => {    // 声明一个空数组,用indexOf寻找如果没有该元素则加入新数组    let newArray = [];    array.forEach(item => {        if(newArray.indexOf(item) === -1) {            newArray.push(item)        }    });    return newArray;}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log(_deleteRepeat(arr));// [ 1, 15, "abc", true, false, undefined, null, NaN, NaN, {}, {} ]

利用 sort() 去重

利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对

时间复杂度为 O(n log n),因为需要对所有元素进行排序操作。因此,这种方法在处理大型数组时可能会导致性能问题。⚠️

注:无法判断NaN{} 重复的情况

const _deleteRepeat = array => {    if (!Array.isArray(array)) {        console.log("type error")        return    }    array = array.sort();    let newArray = [array[0]]    for (let i = 1; i < array.length; i++) {        if (array[i] !== array[i - 1]) {            newArray.push(array[i])        }    }    return newArray}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log(_deleteRepeat(arr))// [ 1, 15, NaN, NaN, {}, {}, "abc", false, null, true, undefined ]

利用对象的属性不能相同的特点进行去重

它会遍历输入的数组,将每个元素作为对象的属性名,如果该属性名在对象中不存在,则将其添加到对象中并将该元素添加到新数组中;如果该属性名已经存在,则不进行任何操作。最终返回去重后的新数组。

注:只能去除数组中的重复值,而不能去除数组中的重复元素(即包含多个值的元素)。如果需要去除数组中的重复元素,可以使用其他方法,比如使用 Set 数据结构或者双重循环等。⚠️

const _deleteRepeat = array => {    if (!Array.isArray(array)) {        console.log("type error")        return    }    let newArray = [];    let obj = {};    array.forEach(item => {        if(!obj[item]) {            obj[item] = true;            newArray.push(item);        }    })    return newArray;}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log(_deleteRepeat(arr))// [ 1, 15, "abc", true, false, undefined, null, NaN, {} ]

利用 includes 去重

声明一个空数组,用 includes 寻找如果没有该元素则加入新数组

时间复杂度为 O(n^2),因为需要对所有元素进行比较和查找操作。因此,这种方法在处理大型数组时可能会导致性能问题。⚠️

注:无法判断{} 重复的情况

const _deleteRepeat = array => {    let newArray = [];    array.forEach(item => {        if (!newArray.includes(item)) {            newArray.push(item)        }    });    return newArray}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log(_deleteRepeat(arr))// [ 1, 15, "abc", true, false, undefined, null, NaN, {}, {} ]

利用 hasOwnProperty 去重

利用 hasOwnProperty 检查对象是否具有指定属性

typeof {}+{} 为 object[object Object],判断有没有空对象,已经有的话 return false,没有就作为对象的属性加进去,值为 true

时间复杂度为 O(n^2),因为需要对所有元素进行比较和查找操作。因此,这种方法在处理大型数组时可能会导致性能问题。⚠️

const _deleteRepeat = array => {    let newArray = [];    let obj = {};    newArray = array.filter(item => {        return obj.hasOwnProperty(typeof item + item) ? false : obj[typeof item +item] = true    });    return newArray}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log(_deleteRepeat(arr))// [ 1, 15, "abc", true, false, undefined, null, NaN, {} ]

利用 filter 去重

该函数使用了 filter() 方法来筛选出数组中的唯一元素。在 filter() 方法中,传入了一个回调函数,该回调函数接受两个参数:item(当前遍历到的元素)和 index(当前元素的索引)。

在回调函数内部,我们使用indexOf() 方法查找该元素在原数组中第一次出现的位置。如果该位置与当前循环的索引相同,则说明该元素是第一次出现,需要保留;否则,说明该元素已经出现过一次,需要过滤掉。

注:无法判断{} 重复的情况(无法判断 NaN)

const _deleteRepeat = array => {    return array.filter((item, index) => {        return array.indexOf(item) === index    })}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log(_deleteRepeat(arr))// [ 1, 15, "abc", true, false, undefined, null, {}, {} ]

利用递归去重

时间复杂度是 O(n^2),因为在每次递归调用时都需要遍历整个数组来查找重复元素。因此,这种方法在处理大型数组时可能会导致性能问题。⚠️

注:无法判断{}NaN重复的情况

const _deleteRepeat = array=>  {    let len = array.length;    // 排序后更加方便去重    array = array.sort();    const loop = index => {        if (index >= 1) {            if (array[index] === array[index - 1]) {                array.splice(index, 1);            }            // 递归loop,然后数组去重            loop(index - 1);        }    }    loop(len - 1);    return array;}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log(_deleteRepeat(arr))// [ 1, 15, NaN, NaN, {}, {}, "abc", false, null, true, undefined ]

利用Map数据结构去重

创建⼀个空 Map 数据结构, 遍历需要去重的数组, 把数组的每⼀个元素作为 key 存到 Map 中。由于 Map 中不会出现相同的 key 值,所以最终得到的就是去重后的结果

时间复杂度为 O(n),因为只需要对所有元素进行一次遍历和查找操作。因此,这种方法在处理大型数组时具有较好的性能。

注:无法判断{} 重复的情况

const _deleteRepeat = array => {    let newArray = [];    let map = new Map();    array.forEach(item => {        if (!map.has(item)) {            map.set(item, true);            newArray.push(item);        }    });    return newArray}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log(_deleteRepeat(arr))// [ 1, 15, "abc", true, false, undefined, null, NaN, {}, {} ]

利用 reduce+includes 去重

reduce() 方法遍历原数组

对于每个元素 item,我们使用 includes() 方法来检查该元素是否已经存在于累加器数组 accumulator 中。如果不存在,则使用 push() 方法将该元素添加到累加器数组中。最后,我们返回累加器数组作为去重后的新数组。

时间复杂度为 O(n^2),因为需要对所有元素进行比较和查找操作。因此,这种方法在处理大型数组时可能会导致性能问题。⚠️

注:无法判断{} 重复的情况

const _deleteRepeat = array => {    return array.reduce((accumulator, item) => {        if (!accumulator.includes(item)) {            accumulator.push(item);        }        return accumulator;    }, []);};let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log(_deleteRepeat(arr))// [ 1, 15, "abc", true, false, undefined, null, NaN, {}, {} ]

[…new Set(arr)]

利用扩展运算符 ...Set 对象去重数组

时间复杂度为 O(n),Set 对象只需要遍历一次原数组即可完成去重操作

注:无法判断{}重复的情况

const _deleteRepeat = array => {    return [...new Set(array)];}let  arr = [1, 1, 15, 15, 'abc', 'abc',          true, true, false, false, undefined, undefined,          null, null, NaN, NaN, {}, {}];console.log(_deleteRepeat(arr))// [ 1, 15, "abc", true, false, undefined, null, NaN, {}, {} ]