Iwen's blog Iwen's blog
首页
  • 前端文章

    • JavaScript
    • Vue
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • 小程序笔记
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • Linux
  • 学习
  • 面试
  • 心情杂货
  • 友情链接
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
复盘
关于

Iwen

不摸鱼的哥哥
首页
  • 前端文章

    • JavaScript
    • Vue
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • 小程序笔记
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • Linux
  • 学习
  • 面试
  • 心情杂货
  • 友情链接
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
复盘
关于
  • Vue

  • Vue进阶

  • CSS

  • ES6

  • Base

  • Core

  • Array

    • 基础方法
    • 数组遍历总结
    • 扁平化
    • 数组去重
      • Set()
      • Map()
      • splice()
      • sort() 相邻比对
      • indexOf()
      • forEach + includes完美版(ok)
      • 另一种优雅的去重方法
    • 判断数组中是否包含某个值
    • 伪数组转换为真数组
    • 数组中强大的reduce
    • 前端模块化
  • Object

  • String

  • Async

  • Browser

  • Http

  • 性能优化

  • 正则

  • 经典总结

  • 设计模式

  • 数据结构

  • 算法

  • 手写

  • TypeScript

  • 复盘
  • Array
Mr.w
2020-11-29

数组去重

# 数组去重

var arr = ['true','true',true,true,0,0,1,1,15,15,false,false,undefined,undefined,null,null,NaN,NaN,'NaN','NaN','a','a',{},{},{a:2},{a:2}];
1

# Set()

不考虑兼容性,这种去重的方法代码最少。这种方法还无法去掉“{}”对象,后面的高阶方法会添加去掉重复“{}”的方法。

function unique (arr) {
  return Array.from(new Set(arr))
}
// or
[...new Set(arr)] 

// ["true", true, 0, 1, 15, false, undefined, null, NaN, "NaN", "a", {}, {}, {a:2}, {a:2}]  // {} 没有去重
1
2
3
4
5
6
7

# Map()

function unique(arr) {
    const newArray = [];
    const tmp = new Map();
    for(let i = 0; i < arr.length; i++){
        if(!tmp.get(arr[i])){
            tmp.set(arr[i], 1);
            newArray.push(arr[i]);
        }
    }
    return newArray;
}

function unique(arr) {
    const tmp = new Map();
    return arr.filter(item => !tmp.has(item) && tmp.set(item, 1) )
}

// ["true", true, 0, 1, 15, false, undefined, null, NaN, NaN, "NaN", "a", {}, {}, {a:2}, {a:2}]  // {} NaN 没有去重
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# splice()

双层循环,外层循环元素,内层循环时比较值。值相同时,删除元素,会改变原数组。

function unique(arr){
    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--;
            }
        }
    }
    return arr;
}
// ["true", true, 0, 1, 15, false, undefined, null, NaN, NaN, "NaN", "a", {}, {}, {a:2}, {a:2}]  // {} 没有去重
1
2
3
4
5
6
7
8
9
10
11
12

# sort() 相邻比对

利用sort()排序方法,先对原数组进行排序,然后再相邻元素比对。

function unique(arr){
    let array = arr.sort();
    let newArr = [];
    for(let i = 0; i < array.length; i++){
        if(array[i] !== array[i + 1]){
            newArr.push(array[i]);
        }
    }
    return newArr;
}
// [0, 1, 15, "NaN", NaN, NaN, {}, {}, {a:2}, {a:2}, "a", false, null, true, "true", undefined]      // NaN、{}没有去重
1
2
3
4
5
6
7
8
9
10
11

# indexOf()

// indexOf,返回数组的第一个值,所以使用filter过滤
function unique(arr) {
  return arr.filter((item, index) => arr.indexOf(item) === index);
}

function unique(arr) {
  const newArray = [];
  arr.forEach(item => {
    if (newArray.indexOf(item) === -1) newArray.push(item);
  });
  return newArray;
}

// [0, 1, 15, "NaN", NaN, NaN, {}, {}, {a:2}, {a:2}, "a", false, null, true, "true", undefined]      // NaN、{}没有去重
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# forEach + includes完美版(ok)

function unique (arr) {
    let newArr = [];
    let obj = {};
    arr.forEach(item => {
        if (typeof item !== 'object') {
            if (!newArr.includes(item)) {
                newArr.push(item)
            }
        } else {
            // 对象
            let str = JSON.stringify(item)
            if (!obj[str]) {
                newArr.push(item)
                obj[str] = 1
            }
        }
    })
    return newArr
}
// [0, 1, 15, "NaN", NaN, NaN, {}, {a:2}, "a", false, null, true, "true", undefined]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 另一种优雅的去重方法

从给数组中的对象去重看Javascript中的reduce() (opens new window)

假设有这样一个数组:

let person = [
     {id: 0, name: "小明"},
     {id: 1, name: "小张"},
     {id: 2, name: "小李"},
     {id: 3, name: "小孙"},
     {id: 1, name: "小周"},
     {id: 2, name: "小陈"},   
]
1
2
3
4
5
6
7
8

我们想去掉数组中id重复的对象,比如同样id为2的两个对象——

{id: 2, name: "小李"}和{id: 2, name: "小陈"} (去掉任何一个都可以) 我们该如何去做呢?

事实上,对于数组对象,传统的去重方法无能为力,至于forEach()、filter()等迭代方法也不好使;真正能做到优雅去重的,是ES5新增加的一个方法——reduce()

reduce()方法接收一个回调函数作为第一个参数,回调函数又接受四个参数,分别是:

  • previousValue => 初始值或上一次回调函数叠加的值;
  • currentValue => 本次回调(循环)将要执行的值;
  • index =>“currentValue”的索引值;
  • arr => 数组本身;

reduce()方法返回的是最后一次调用回调函数的返回值;

let log = console.log.bind(console);
let arr = [1,2,3,4,5,6];
arr = arr.reduce((previousValue, currentValue) => {
     return previousValue + currentValue; //返回的是最后一次调用回调函数的值,15+6;
})
log(arr); // 21
1
2
3
4
5
6

可以看出,上面代码的最终结果就是1+2+3+4+5+6 = 21;

此外,reduce还可以接收第二参数initialValue,用来声明回调函数(第一个参数)的previousValue的类型和初始值;

let log = console.log.bind(console);
let arr = [1,2,3,4,5,6];
arr = arr.reduce((previousValue,currentValue) => {
     return previousValue + currentValue;
},0) //指定cur的类型为Number并且初始值为0,当设为1时,最终打印的值为22
log(arr); // 21
1
2
3
4
5
6

需要注意的是,如果设置了initialValue的值,第一次执行回调函数的previousValue的值等于initialValue,此时查看当前索引(index)为0;但如果不设置initialValue的值,previousValue的值为数组的第一项,并且索引值(index)为1;也就是说,不设置初始值的话reduce()方法实际是从第二次循环开始的!

现在让我们回到文章开头的那个数组:

let log = console.log.bind(console);
let person = [
     {id: 0, name: "小明"},
     {id: 1, name: "小张"},
     {id: 2, name: "小李"},
     {id: 3, name: "小孙"},
     {id: 1, name: "小周"},
     {id: 2, name: "小陈"},   
];

let obj = {};

person = person.reduce((cur,next) => {
    if(!obj[next.id]) obj[next.id] = true && cur.push(next);
    return cur;
},[]) //设置cur默认类型为数组,并且初始值为空的数组
log(person);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

打印person后,我们就可以得到去重后的数组。

当然, redecu()除了累加和去重外,功能还有很多,比如可以扁平化多维数组——

var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
    return a.concat(b);
}, []); // [0,1,2,3,4,5]
1
2
3

再说句题外的,提到去重,很多人都会想到ES6的Set;不过根据实验,Set还是适合对基本类型的去重,如果Set中的每一项是对象的话,是不会去重的,j即使有的对象一模一样——

let arr = new Set([
    {id: 0, name: "小明"},
    {id: 0, name: "小明"},
    {id: 0, name: "小明"},
    {id: 0, name: "小明"}      
]);
console.log([...arr]); //依旧是这4个对象
1
2
3
4
5
6
7
扁平化
判断数组中是否包含某个值

← 扁平化 判断数组中是否包含某个值→

最近更新
01
flex布局页面自适应滚动条问题
12-28
02
前后端分离开发请求接口跨域如何携带cookie的问题
12-28
03
怎么实现div长宽比固定width-height4比3
12-28
更多文章>
Theme by Vdoing | Copyright © 2017-2022 Iwen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式