JS数组去重方法总结

JS数组去重

数组去重,做为前端面试中的经典题,常常会被说起到。前端

本文就数组去重的方法,作了些许整理,方便理解与总结。面试

最原始的方法

在不借助JS数组的相关API的状况下,咱们来看下数组去重最原始的实现方法:数组

var array = [1,1,'1','1']
function unique(array) {
    var res = []
    for (var i=0,arrlen=array.length;i<arrlen;i++) {
        for (var j = 0,reslen=res.length;j<reslen;j++) {
            if (array[i] === res[j]) {
                break
            }
        }
        if (j === reslen) {
            res.push(array[i])
        }
    }
    return res
}
console.log(unique(array)) //[1,'1']
复制代码

在这个方法中,咱们使用循环嵌套,最外层循环 array,里面循环 res,若是 array[i] 的值跟 res[j] 的值相等,就跳出循环,若是都不等于,说明元素是惟一的,这时候 j 的值就会等于 res 的长度,根据这个特色进行判断,将值添加进 res。数据结构

这个最原始的方法,有着一个很明显的优势,兼容性好。ui

indexOf

借助indexOf,咱们能够稍稍简化下内层循环:spa

var array = [1,1,'1','1']
function unique(array) {
    var res = []
    for (var i=0,len=array.length;i<len;i++) {
        var current = array[i]
        if (res.indexOf(current) === -1) {
            res.push(current)
        }
    }
    return res
}
console.log(unique(array)) // [1,'1']
复制代码

filter

ES5提供了filter方法,咱们能够借助这个方法来简化外层循环,好比改写使用indexOf的去重方法:code

var array = [1,2,1,1,'1']
function unique(array) {
    var res = array.filter(function(item,index,array) {
        return array.indexOf(item) === index
    })
    return res
}
console.log(unique(array)) // [1,2,'1']
复制代码

对象键值对去重

对象键值对去重是利用一个空的object对象,咱们把数组的值存成object对象的key值,好比让object[array[item1]] = true,在判断另外一个值object[array[item2]]存在的话,就说明该值是重复的:对象

var array1 = [1,2,1,2,1]
var array2 = [1, 2, 1, 1, '1'];
function unique(array) {
    var obj = {}
    return array.filter(function(item, index, array){
        return obj.hasOwnProperty(item) ? false : (obj[item] = true)
    })
}
console.log(unique(array1)) //[1,2]
console.log(unique(array2)) // [1, 2]
复制代码

很明显,如今这个方法是有问题,由于1和'1'是不一样的,可是object[1]object['1']倒是同一个引用,由于对象的key值只能是字符串。字符串

那么咱们使用 typeof item + item 拼成字符串做为key值来避免这个问题:string

var array = [1,2,1,1,'1']
function unique(array) {
    var obj = {}
    return array.filter(function(item,index,array) {
        return obj.hasOwnProperty(typeof item+item)?false:(obj[typeof item+item] = true)
    })
}
console.log(unique(array)) //[1,2,'1']
复制代码

But,若是数组项中若是存在对象时,好比{value:1}、{value:2},因为typeof item + item的结果都会是object[object Object],不过咱们可使用JSON.stringfy()将对象序列化来避免相同的键值。因此可这样改写unique:

var array = [1,1,2,2,'1',{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)) // [1,2,'1',{value: 1}, {value: 2}]
复制代码

ES6的Set对象和Map对象

Set对象是ES6中的新数据结构

根据MDN描述:

Set对象是值的集合,你能够按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是惟一的。

也就是说,Set对象相似于数组,可是成员的值都是惟一的,没有重复的值。

那么借助于Set,数组去重将变得异常简单:

var array = [1, 2, 1, '1']
function unique(array) {
   return Array.from(new Set(array))
}
console.log(unique(array)) // [1, 2, "1"]
复制代码

除此以外,咱们也可使用ES6中的Map对象来改写unique:

var array = [1, 2, 1, '1'];
function unique(array) {
    const seen = new Map()
    return array.filter(function(item,index,array) {
        return !seen.has(item) && seen.set(item,1)
    })
}
console.log(unique(array)) //[1,2,'1']
复制代码

不一样数组去重方法结果的对比

假设有这样一个数组:

var array = [1, 1, '1', '1', null, null, undefined, undefined, new String('1'), new String('1'), /a/, /a/, NaN, NaN];
复制代码

用不一样的数组去重方法,获得的结果会有什么不一样吗?

为此,特意整理了一个列表,以表差别

方法 结果 说明
for循环 [1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN] 对象和 NaN 不去重
indexOf [1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN] 对象和 NaN 不去重
filter+indexOf [1, "1", null, undefined, String, String, /a/, /a/] 对象不去重 NaN 会被忽略掉
对象键值对去重 [1, "1", null, undefined, String, /a/, NaN] 所有去重
Set对象去重 [1, "1", null, undefined, String, String, /a/, /a/, NaN] 对象不去重 NaN 去重

至此,经常使用的数组去重方法都已展现在这里,对于不一样场景的使用也作了对比,方便理解与应用。

相关文章
相关标签/搜索