JavaScript學(xué)習(xí)筆記之?dāng)?shù)組去重
推薦閱讀:JavaScript學(xué)習(xí)筆記之?dāng)?shù)組的增、刪、改、查
JavaScript學(xué)習(xí)筆記之?dāng)?shù)組求和方法
JavaScript學(xué)習(xí)筆記之?dāng)?shù)組隨機(jī)排序
話說(shuō)面試常會(huì)碰到面試官會(huì)問(wèn)JavaScript實(shí)現(xiàn)數(shù)組去重的問(wèn)題,最近剛好在學(xué)習(xí)有關(guān)于JavaScript數(shù)組相關(guān)的知識(shí),趁此機(jī)會(huì)整理了一些有關(guān)于JavaScript數(shù)組去重的方法。
下面這些數(shù)組去重的方法是自己收集和整理的,如有不對(duì)希望指正文中不對(duì)之處。
雙重循環(huán)去重
這個(gè)方法使用了兩個(gè)for循環(huán)做遍歷。整個(gè)思路是:
構(gòu)建一個(gè)空數(shù)組用來(lái)存放去重后的數(shù)組
外面的for循環(huán)對(duì)原數(shù)組做遍歷,每次從數(shù)組中取出一個(gè)元素與結(jié)果數(shù)組做對(duì)比
如果原數(shù)組取出的元素與結(jié)果數(shù)組元素相同,則跳出循環(huán);反之則將其存放到結(jié)果數(shù)組中
代碼如下:
Array.prototype.unique1 = function () { // 構(gòu)建一個(gè)新數(shù)組,存放結(jié)果 var newArray = [this[0]]; // for循環(huán),每次從原數(shù)組中取出一個(gè)元素 // 用取出的元素循環(huán)與結(jié)果數(shù)組對(duì)比 for (var i = 1; i < this.length; i++) { var repeat = false; for (var j=0; j < newArray.length; j++) { // 原數(shù)組取出的元素與結(jié)果數(shù)組元素相同 if(this[i] == newArray[j]) { repeat = true; break; } } if(!repeat) { // 如果結(jié)果數(shù)組中沒(méi)有該元素,則存放到結(jié)果數(shù)組中 newArray.push(this[i]); } } return newArray; }
假設(shè)我們有一個(gè)這樣的數(shù)組:
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1',`2`]; arr.unique1(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5]
據(jù)說(shuō)這種方法比較耗時(shí),費(fèi)性能。簡(jiǎn)單做個(gè)測(cè)試(測(cè)試方法寫得比較拙逼):
function test () { var arr = []; for (var i = 0; i < 1000000; i++) { arr.push(Math.round(Math.random(i) * 10000)); } doTest(arr, 1); } function doTest(arr, n) { var tStart = (new Date()).getTime(); var re = arr.unique1(); var tEnd = (new Date()).getTime(); console.log('雙重循環(huán)去重方法使用時(shí)間是:' + (tEnd - tStart) + 'ms'); return re; } test();
在Chrome控制器運(yùn)行上面的代碼,測(cè)試雙重循環(huán)去重所費(fèi)時(shí)間:11031ms。
上面的方法可以使用forEach()方法和indexOf()方法模擬實(shí)現(xiàn):
function unique1() { var newArray = []; this.forEach(function (index) { if (newArray.indexOf(index) == -1) { newArray.push(index); } }); return newArray; }
通過(guò)unique1.apply(arr)或unique1.call(arr)調(diào)用。不過(guò)這種方法效率要快得多,同樣的上面測(cè)試代碼,所費(fèi)時(shí)間5423ms,幾乎快了一半。
排序遍歷去重
先使用sort()方法對(duì)原數(shù)組做一個(gè)排序,排完序之后對(duì)數(shù)組做遍歷,并且檢查數(shù)組中的第i個(gè)元素與結(jié)果數(shù)組中最后一個(gè)元素是否相同。如果不同,則將元素放到結(jié)果數(shù)組中。
Array.prototype.unique2 = function () { // 原數(shù)組先排序 this.sort(); // 構(gòu)建一個(gè)新數(shù)組存放結(jié)果 var newArray = []; for (var i = 1; i < this.length; i++) { // 檢查原數(shù)中的第i個(gè)元素與結(jié)果中的最后一個(gè)元素是否相同 // 因?yàn)榕判蛄?,所以重?fù)元素會(huì)在相鄰位置 if(this[i] !== newArray[newArray.length - 1]) { // 如果不同,將元素放到結(jié)果數(shù)組中 newArray.push(this[i]); } } return newArray; }
例如:
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique2(); // ["1", 1, 2, "2", 3, 32, 34, 4, 5, 56, "a", "b", "c"]
這種方法有兩個(gè)特色:
去重后的數(shù)組會(huì)做排序,主要是因?yàn)樵瓟?shù)在去重前做了排序
去重后的數(shù)組,與數(shù)字相同的數(shù)字字符無(wú)法區(qū)分,比如'1'和1
使用同樣的方法,測(cè)試所費(fèi)時(shí)間:1232ms。
對(duì)象鍵值對(duì)法
這種去重方法實(shí)現(xiàn)思路是:
創(chuàng)建一個(gè)JavaScript對(duì)象以及新數(shù)組
使用for循環(huán)遍歷原數(shù)組,每次取出一個(gè)元素與JavaScript對(duì)象的鍵做對(duì)比
如果不包含,將存入對(duì)象的元素的值推入到結(jié)果數(shù)組中,并且將存入object對(duì)象中該屬性名的值設(shè)置為1
代碼如下:
Array.prototype.unique3 = function () { // 構(gòu)建一個(gè)新數(shù)組存放結(jié)果 var newArray = []; // 創(chuàng)建一個(gè)空對(duì)象 var object = {}; // for循環(huán)時(shí),每次取出一個(gè)元素與對(duì)象進(jìn)行對(duì)比 // 如果這個(gè)元素不重復(fù),則將它存放到結(jié)果數(shù)中 // 同時(shí)把這個(gè)元素的內(nèi)容作為對(duì)象的一個(gè)屬性,并賦值為1, // 存入到第2步建立的對(duì)象中 for (var i = 0; i < this.length; i++){ // 檢測(cè)在object對(duì)象中是否包含遍歷到的元素的值 if(!object[typeof(this[i]) + this[i]]) { // 如果不包含,將存入對(duì)象的元素的值推入到結(jié)果數(shù)組中 newArray.push(this[i]); // 如果不包含,存入object對(duì)象中該屬性名的值設(shè)置為1 object[typeof(this[i]) + this[i]] = 1; } } return newArray; }
運(yùn)行前面的示例:
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique3(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
同樣的,不同的鍵可能會(huì)被誤認(rèn)為一樣;例如: a[1]、a["1"] 。這種方法所費(fèi)時(shí)間:621ms。 這種方法所費(fèi)時(shí)間是最短,但就是占用內(nèi)存大一些。
除了上面幾種方法,還有其他幾種方法如下:
// 方法四 Array.prototype.unique4 = function () { // 構(gòu)建一個(gè)新數(shù)組存放結(jié)果 var newArray = []; // 遍歷整個(gè)數(shù)組 for (var i = 0; i < this.length; i++) { // 遍歷是否有重復(fù)的值 for (j = i + 1; j < this.length; j++) { // 如果有相同元素,自增i變量,跳出i的循環(huán) if(this[i] === this[j]) { j = ++i; } } // 如果沒(méi)有相同元素,將元素推入到結(jié)果數(shù)組中 newArray.push(this[i]); } return newArray; }
Chrome測(cè)試結(jié)果
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique4(); // ["a", 1, 3, 4, 56, 32, 34, 2, "b", "c", 5, "1", "2"]
同樣的,1和'1'無(wú)法區(qū)分。
// 方法五 Array.prototype.unique5 = function () { // 構(gòu)建一個(gè)新數(shù)組存放結(jié)果 var newArray = []; // 遍歷整個(gè)數(shù)組 for (var i = 0; i < this.length; i++) { // 如果當(dāng)前數(shù)組的第i值保存到臨時(shí)數(shù)組,那么跳過(guò) var index = this[i]; // 如果數(shù)組項(xiàng)不在結(jié)果數(shù)組中,將這個(gè)值推入結(jié)果數(shù)組中 if (newArray.indexOf(index) === -1) { newArray.push(index); } } return newArray; }
Chrome測(cè)試結(jié)果:
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique6(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
同樣的,類似于1和'1'無(wú)法區(qū)分。所費(fèi)時(shí)間:14361ms。
// 方法六 Array.prototype.unique6 = function () { return this.reduce(function (newArray, index) { if(newArray.indexOf(index) < 0) { newArray.push(index); } return newArray; },[]); }
測(cè)試結(jié)果如下:
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique6(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
所費(fèi)時(shí)間:16490ms。
// 方法七 Array.prototype.unique7 = function(){ var newArray; newArray = this.filter(function (ele,i,arr) { return arr.indexOf(ele) === i; }); return newArray; }
測(cè)試結(jié)果:
var arr = [1,2,3,4,'a','b',1,3,4,56,32,34,2,'b','c',5,'1','2']; arr.unique6(); // [1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
所費(fèi)時(shí)間:13201ms。
方法雖然很多種,但相比下來(lái),下面這種方法是較為優(yōu)秀的方案:
Array.prototype.unique3 = function () { // 構(gòu)建一個(gè)新數(shù)組存放結(jié)果 var newArray = []; // 創(chuàng)建一個(gè)空對(duì)象 var object = {}; // for循環(huán)時(shí),每次取出一個(gè)元素與對(duì)象進(jìn)行對(duì)比 // 如果這個(gè)元素不重復(fù),則將它存放到結(jié)果數(shù)中 // 同時(shí)把這個(gè)元素的內(nèi)容作為對(duì)象的一個(gè)屬性,并賦值為1, // 存入到第2步建立的對(duì)象中 for (var i = 0; i < this.length; i++){ // 檢測(cè)在object對(duì)象中是否包含遍歷到的元素的值 if(!object[typeof(this[i]) + this[i]]) { // 如果不包含,將存入對(duì)象的元素的值推入到結(jié)果數(shù)組中 newArray.push(this[i]); // 如果不包含,存入object對(duì)象中該屬性名的值設(shè)置為1 object[typeof(this[i]) + this[i]] = 1; } } return newArray; }
但在ES6去重還有更簡(jiǎn)單,更優(yōu)化的方案,比如:
// ES6 function unique (arr) { const seen = new Map() return arr.filter((a) => !seen.has(a) && seen.set(a, 1)) } // or function unique (arr) { return Array.from(new Set(arr)) }
以上所述是小編給大家介紹的JavaScript學(xué)習(xí)筆記之?dāng)?shù)組去重,希望對(duì)大家有所幫助!
相關(guān)文章
在JavaScript里嵌入大量字符串常量的實(shí)現(xiàn)方法
在JavaScript文件里嵌入大量字符串常量是經(jīng)常遇到的事。有時(shí)為了省事,就把一些界面的HTML和CSS直接寫在JS文件里2013-07-07JS實(shí)現(xiàn)字符串中去除指定子字符串方法分析
這篇文章主要介紹了JS實(shí)現(xiàn)字符串中去除指定子字符串方法,結(jié)合實(shí)例形式分析了javascript使用字符串替換與分割、聚合兩種子字符串去除相關(guān)操作技巧,需要的朋友可以參考下2018-05-05ymPrompt的doHandler方法來(lái)實(shí)現(xiàn)獲取子窗口返回值的方法
今天在寫頁(yè)面時(shí)用到了ymPrompt的win方法來(lái)彈出一個(gè)窗口。由于要用到獲取子窗口返回來(lái)的值判斷是否刷新父窗口,在ymPrompt的組件Demo中一直沒(méi)有找到合適的方法實(shí)現(xiàn)2010-06-06Bootstrap在線電子商務(wù)網(wǎng)站實(shí)戰(zhàn)項(xiàng)目5
這篇文章主要為大家分享了Bootstrap在線電子商務(wù)網(wǎng)站實(shí)戰(zhàn)項(xiàng)目,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10使用documentElement正確取得當(dāng)前可見區(qū)域的大小
如何取得當(dāng)前瀏覽器里面可見區(qū)域的大???其他方法都不適用,只有documentElement才可以,需要的朋友可以參考下2014-07-07