最原始的方法:雙層循環(huán)
var array = [1, 1, '1', '1'];
function unique(array) {
// res用來存儲結(jié)果
var res = [];
for (var i = 0, arrayLen = array.length; i < arrayLen; i++) {
for (var j = 0, resLen = res.length; j < resLen; j++ ) {
if (array[i] === res[j]) {
break;
}
}
// 如果array[i]是唯一的涯冠,那么執(zhí)行完循環(huán)磁滚,j等于resLen
if (j === resLen) {
res.push(array[i])
}
}
return res;
}
console.log(unique(array)); // [1, "1"]
在這個方法中拣挪,我們使用循環(huán)嵌套擦酌,最外層循環(huán) array,里面循環(huán) res菠劝,如果
array[i] 的值跟 res[j] 的值相等赊舶,就跳出循環(huán),如果都不等于赶诊,說明元素是
唯一的笼平,這時候 j 的值就會等于 res 的長度,根據(jù)這個特點(diǎn)進(jìn)行判斷舔痪,將值添
加進(jìn) res寓调。看起來很簡單吧锄码,之所以要講一講這個方法夺英,是因?yàn)椤嫒菪院茫?/p>
indexOf
我們可以用 indexOf 簡化內(nèi)層的循環(huán):
var array = [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));
排序后去重
var array = [1, 1, '1'];
function unique(array) {
var res = [];
var sortedArray = array.concat().sort();
var seen;
for (var i = 0, len = sortedArray.length; i < len; i++) {
// 如果是第一個元素或者相鄰的元素不相同
if (!i || seen !== sortedArray[i]) {
res.push(sortedArray[i])
}
seen = sortedArray[i];
}
return res;
}
console.log(unique(array));
如果我們對一個已經(jīng)排好序的數(shù)組去重,這種方法效率肯定高于使用 indexOf滋捶。
unique API
知道了這兩種方法后痛悯,我們可以去嘗試寫一個名為 unique 的工具函數(shù),我們根據(jù)一個參數(shù) isSorted 判斷傳入的數(shù)組是否是已排序的炬太,如果為 true,我們就判斷相鄰元素是否相同驯耻,如果為 false亲族,我們就使用 indexOf 進(jìn)行判斷
var array1 = [1, 2, '1', 2, 1];
var array2 = [1, 1, '1', 2, 2];
// 第一版
function unique(array, isSorted) {
var res = [];
var seen = [];
for (var i = 0, len = array.length; i < len; i++) {
var value = array[i];
if (isSorted) {
if (!i || seen !== value) {
res.push(value)
}
seen = value;
}
else if (res.indexOf(value) === -1) {
res.push(value);
}
}
return res;
}
console.log(unique(array1)); // [1, 2, "1"]
console.log(unique(array2, true)); // [1, "1", 2]
優(yōu)化
盡管 unqique 已經(jīng)可以試下去重功能,但是為了讓這個 API 更加強(qiáng)大可缚,
我們來考慮一個需求:
新需求:字母的大小寫視為一致霎迫,比如'a'和'A',保留一個就可以了帘靡!
雖然我們可以先處理數(shù)組中的所有數(shù)據(jù)知给,比如將所有的字母轉(zhuǎn)成小寫,然后再
傳入unique函數(shù),但是有沒有方法可以省掉處理數(shù)組的這一遍循環(huán)涩赢,直接就在
去重的循環(huán)中做呢戈次?讓我們?nèi)ネ瓿蛇@個需求:
var array3 = [1, 1, 'a', 'A', 2, 2];
// 第二版
// iteratee 英文釋義:迭代 重復(fù)
function unique(array, isSorted, iteratee) {
var res = [];
var seen = [];
for (var i = 0, len = array.length; i < len; i++) {
var value = array[i];
var computed = iteratee ? iteratee(value, i, array) : value;
if (isSorted) {
if (!i || seen !== computed) {
res.push(value)
}
seen = computed;
}
else if (iteratee) {
if (seen.indexOf(computed) === -1) {
seen.push(computed);
res.push(value);
}
}
else if (res.indexOf(value) === -1) {
res.push(value);
}
}
return res;
}
console.log(unique(array3, false, function(item){
return typeof item == 'string' ? item.toLowerCase() : item
})); // [1, "a", 2]
在這一版也是最后一版的實(shí)現(xiàn)中,函數(shù)傳遞三個參數(shù):
array:表示要去重的數(shù)組筒扒,必填
isSorted:表示函數(shù)傳入的數(shù)組是否已排過序怯邪,如果為 true,將會采用更快的
方法進(jìn)行去重
iteratee:傳入一個函數(shù)花墩,可以對每個元素進(jìn)行重新的計算悬秉,然后根據(jù)處理的結(jié)
果進(jìn)行去重
至此,我們已經(jīng)仿照著 underscore 的思路寫了一個 unique 函數(shù)冰蘑。