數組去重,做爲前端面試中的經典題,常常會被說起到。前端
本文就數組去重的方法,作了些許整理,方便理解與總結。面試
在不借助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,咱們能夠稍稍簡化下內層循環: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']
複製代碼
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}]
複製代碼
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 去重 |
至此,經常使用的數組去重方法都已展現在這裏,對於不一樣場景的使用也作了對比,方便理解與應用。