數組去重的各種方式對比

數組去重,是一個老生常談的問題了,在各廠的面試中也會有所提及,接下來就來細數一下各種數組去重的方式吧;

對于以下各種方式都統一命名為 unique,公用代碼如下:

// 生成一個包含100000個[0,50000)隨機數的數組
var arr = [];
for(var i = 0; i < 100000; i++) {arr.push(Math.floor(Math.random() * 50000));
}
Array.prototype.unique = function() { // 算法 };
console.log(arr.unique());  // 一個已經去重的數組
復制代碼

1、雙重遍歷

雙重遍歷的實現主要是通過兩次遍歷的對比,生成一個新的,不含重復數據的數組;

其實現方式有如下兩種:

/** 第一種實現方式:* 對數組的每個元素在推入新數組之前與新數組中每個元素比較,如果沒有相同值則推入*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [], isRepeat;for(var i = 0, length = this.length; i < length; i++) {isRepeat = false;for(var j = 0, newLength = newArray.length; j < newLength; j++) {if(this[i] === newArray[j]) {isRepeat = true;break;}}if(!isRepeat) newArray.push(this[i]);}return newArray;
};
/** 第二種實現方式* 將數組的每個元素與其后面所有元素做遍歷對比,若有相同的值,則不推入新數組,*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [], isRepeat;for(var i = 0, length = this.length; i < length; i++) {isRepeat = false;for(var j = i + 1; j < length; j++) {if(this[i] === this[j]) {isRepeat = true;break;}}if(!isRepeat) newArray.push(this[i]);}return newArray;
};// 實測耗時
// 方式一:2372 ms
// 方式二:4025 ms
復制代碼

2、Array.prototype.indexOf()

通過 indexOf 方法查詢值在數組中的索引,并通過對索引的判斷來實現去重;

主要實現方式有下面兩種:

/*** 第一種實現方式* 結合數組的 filter 方法,將相同值的第一個合并到一個新的數組中返回* indexOf 檢測到的索引為出現當前值的第一個位置* 若 indexOf 檢測到的索引和當前值索引不相等則說明前面有相同的值*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');return this.filter(function(item, index, array) {return array.indexOf(item) === index;});
};
/*** 第二種實現方式* 對數組進行遍歷,并將每個元素在新數組中匹配* 若新數組中無該元素,則插入*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [];this.forEach(function(item) {if(newArray.indexOf(item) === -1) newArray.push(item);});return newArray;
};// 實測耗時
// 方式一:3972 ms
// 方式二:2650 ms
復制代碼

3、Array.prototype.sort()

sort 方法可對數組進行排序,此時相同的值就會被排到一起,然后通過相鄰元素比較就可知是否有相同值了;

舉個栗子:

/*** 第一種實現方式* 先將數組通過 sort 排序* 再遍歷數組,將每個元素與其前面一個元素比較* 若值不同則表示該元素第一次出現,則插入到新數組*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [];this.sort();for(var i = 0, length = this.length; i < length; i++) {if(this[i] !== this[i - 1]) newArray.push(this[i]);}return newArray;
};
/*** 第二種實現方式* 先將數組通過 sort 排序* 再遍歷數組,將每個元素與插入到新數組中的最后一個元素比較* 若值不同則表示該元素第一次出現,則插入到新數組*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [];this.sort();for(var i = 0, length = this.length; i < length; i++) {if(this[i] !== newArray[newArray.length - 1]) newArray.push(this[i]);}return newArray;
};// 實測耗時
// 方式一:105 ms
// 方式二:112 ms
復制代碼

由于方式二在每次比較的時候需要重新計算一次 newArray.length 故會稍微比方式一慢一點;

3、Array.prototype.includes(searchElm, fromIndex)

該方法判斷數組中是否存在指定元素

參數:

  • searchElm:需要查找的元素
  • fromIndex:開始查找索引位置(若未負值,則從 array.length - fromIndex 位置開始查找

返回值:

  • Boolean:數組中是否存在該元素
/*** 實現方式* 遍歷數組,通過 includes 判斷每個值在新數組中是否存在* 若不存在,則將值插入到新數組中*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArray = [];this.forEach(function(item) {if(!newArray.includes(item)) newArray.push(item);});return newArray;
};// 實測耗時:2597 ms
復制代碼

4、Array.prototype.reduce()

/*** 實現方式* 先將數組進行排序* 然后利用 reduce 迭代和累加的特性,將符合要求的元素累加到新數組并返回*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');return this.sort().reduce(function(newArr, curr) {if(newArr[newArr.length - 1] !== curr) newArr.push(curr);return newArr;}, []);
};// 實測耗時:127 ms
復制代碼

5、對象的鍵值對

利用對象的 key 不能重復的特性來去重; 之前看到有人使用對象的鍵值對去重的時候,直接將數組的每個值設置為對象的 keyvalue 都為1,每出現一個相同的值時就 value++,這樣既可以去重,又可以知道對應的值出現的次數,例如:

var array = ['a', 'b', 'c', 'a', 'a', 'c'];
var newArr = [], obj = {};
array.forEach(function(item) {if(obj[item]) {obj[item]++;} else {obj[item] = 1;newArr.push(item);}
});
console.log(newArr); // ["a", "b", "c"]
console.log(obj);    // {a: 3, b: 1, c: 2}
復制代碼

咋一看好像很完美,可是仔細一想,會發現有以下幾點原因:

  • 若數組的值中出現了隱式類型轉換成字符串后相等的值,則無法區分,例如 '1' 和 1;
  • 若數組中的值有對象,寫成 key 之后都是 [object Object],無法區分;

解決方案:

若元素值的類型為 object,則通過 JSON.stringify 方法進行轉換;

Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var newArr = [], obj = {};this.forEach(function(item) {if(!obj[typeof item + JSON.stringify(item)]) {obj[typeof item + JSON.stringify(item)] = 1;newArr.push(item);}});return newArr;
};// 實測耗時:142 ms
復制代碼

6、Set

Set 對象的特性就是其中的值是唯一的,可利用該特性很便捷的處理數組去重的問題;

/*** 實現方式一* 將數組轉換成 Set 對象* 通過 Array.from 方法將 Set 對象轉換為數組*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');var set = new Set(this);return Array.from(set);
};// 實測耗時:45 ms/*** 實現方式二* 將數組轉換成 Set 對象* 通過 Array.from 方法將 Set 對象轉換為數組*/
Array.prototype.unique = function() {if(!Array.isArray(this)) throw new Error('Type Error: The target should be an Array!');return [...new Set(this)];
};// 實測耗時:65 ms
復制代碼

由以上耗時結果可以看出:

  • filter, forEach 等方法都會對全數組進行遍歷;
  • indexOf, for+break, includes 等方法會對數組遍歷,在滿足條件的地方跳出遍歷

轉載于:https://juejin.im/post/5b2612e36fb9a00e50312e2d

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/254326.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/254326.shtml
英文地址,請注明出處:http://en.pswp.cn/news/254326.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux平臺Makefile文件的編寫基礎篇和GCC參數詳解

問&#xff1a;gcc中的-I.是什么意思。。。。看到了有的是gcc -I. -I/usr/xxxxx..那個-I.是什么意思呢 最佳答案 答&#xff1a;-Ixxx 的意思是除了默認的頭文件搜索路徑(比如/usr/include等&#xff09;外&#xff0c;同時還在路徑xxx下搜索需要被引用的頭文件。 所以你的gcc …

舊知識打造新技術--AJAX學習總結

AJAX是將舊知識在新思想的容器內進行碰撞產生的新技術&#xff1a;推翻傳統網頁的設計技術。改善用戶體驗的技術。 學習AJAX之初寫過一篇《與Ajax的初次謀面》。當中都僅僅是一些自己淺顯的理解&#xff0c;這次就總結一下它在歷史長河中的重要地位。 【全】 AJAX全稱為Asnychr…

C#數組基本操作

文章目錄簡介數組排序和反轉語法實例查找數組元素語法實例數組元素求和、最大值、最小值、平均值語法實例數組字符串相互轉化語法實例在字符串中查找、刪除字符數組元素語法實例博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 簡介 C#提供了許…

redis(一)--認識redis

Redis官網對redis的定義是&#xff1a;“Redis is an open source, BSD licensed, advanced key-value cache and store”&#xff0c;可以看出&#xff0c;Redis是一種鍵值系統&#xff0c;可以用來緩存或存儲數據。Redis是“Remote Dictionary Server”&#xff08;遠程字典服…

轉:如何用gcc編譯生成動態鏈接庫*.so文件 動態庫

轉&#xff1a;如何編譯.so動態庫問&#xff1a;我源文件為main.c, x.c, y.c, z.c,頭文件為x.h,y.h,z.h如何編譯成.so動態庫&#xff1f;編譯器用gcc最好能給出詳細參數解釋&#xff0c;謝謝答&#xff1a;# 聲稱動代連接庫&#xff0c;假設名稱為libtest.sogcc x.c y.c z.c -f…

工業鏡頭的主要參數與選型

文章目錄簡介1、鏡頭的分類(1) 以鏡頭安裝分類(2) 以攝像頭鏡頭規格分類(3) 以鏡頭光圈分類(4) 以鏡頭的視場大小分類(5) 從鏡頭焦距上分2、選擇鏡頭的技術依據(1) 鏡頭的成像尺寸(2) 鏡頭的分辨率(3) 鏡頭焦距與視野角度(4) 光圈或通光量3、變焦鏡頭&#xff08;zoom lens&…

SQLSEVER 中的那些鍵和約束

SQL Server中有五種約束類型&#xff0c;各自是 PRIMARY KEY約束、FOREIGN KEY約束、UNIQUE約束、DEFAULT約束、和CHECK約束。查看或者創建約束都要使用到 Microsoft SQL Server Managment Studio。1. PRIMARY KEY約束 在表中常有一列或多列的組合&#xff0c;其值能唯一標識表…

數據庫 sqlite 進階

http://www.cppblog.com/czy463/archive/2013/12/16/204816.html 董淳光 前序&#xff1a; Sqlite3 的確很好用。小巧、速度快。但是因為非微軟的產品&#xff0c;幫助文檔總覺得不夠。這些天再次研究它&#xff0c;又有一些收獲&#xff0c;這里把我對 sqlite3 的研究列出來&a…

形象的列舉-C# 枚舉

文章目錄簡介例子分析點撥博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 簡介 枚舉類型用于聲明一組命名常數。 定義枚舉類型語法格式如下&#xff1a;enum 枚舉數組名{枚舉成員列表};例如&#xff1a; enum week{星期一&#xff0c;星期二…

Confluence 6 手動備份站點

2019獨角獸企業重金招聘Python工程師標準>>> Confluence 被配置自動備份數據&#xff0c;使用壓縮的 XML 格式。同時你也可以通過 Confluence 的 管理員控制臺&#xff08;Administration Console&#xff09;手動進行備份。 你需要具有 System Administrator 權限才…

編寫高質量的Makefile

分類&#xff1a; c/c研究 GNU&amp;LINUX2010-09-12 15:31163人閱讀 評論(0)收藏舉報源地址 &#xff1a;http://acm.hrbeu.edu.cn/forums/index.php?showtopic1827&st0&gopid8924&#entry8924 一、前言 回想自己的第一個Makefile&#xff0c;是這個樣子的 …

第六篇:python基礎之文件處理

第六篇&#xff1a;python基礎之文件處理 閱讀目錄 一.文件處理流程二.基本操作2.1 文件操作基本流程初探2.2 文件編碼2.3 文件打開模式2.4 文件內置函數flush2.5 文件內光標移動2.6 open函數詳解2.7 上下文管理2.8 文件的修改一.文件處理流程 打開文件&#xff0c;得到文件句柄…

前端每日實戰:56# 視頻演示如何用純 CSS 描述程序員的生活

效果預覽 按下右側的“點擊預覽”按鈕可以在當前頁面預覽&#xff0c;點擊鏈接可以全屏預覽。 https://codepen.io/comehope/pen/YvYVvY 可交互視頻 此視頻是可以交互的&#xff0c;你可以隨時暫停視頻&#xff0c;編輯視頻中的代碼。 請用 chrome, safari, edge 打開觀看。 ht…

從特殊到一般-C#中的類

文章目錄類的概念類的定義實例例子分析類的成員數據成員屬性成員方法成員靜態成員博主寫作不容易&#xff0c;孩子需要您鼓勵 萬水千山總是情 , 先點個贊行不行 類的概念 在日常生活中&#xff0c;類是對具有相同特性的一類是物的抽象。比如水果是一個類&#xff0c;它是對…

Chapter 1 First Sight——30

The girl sitting there giggled. Id noticed that his eyes were black — coal black. 那個坐在那里的女孩笑著。我注意到她的眼睛是很色的--炭黑色的。 Mr. Banner signed my slip and handed me a book with no nonsense about introductions. Banner 先生簽了我的名字然后…

GPU 與CPU的作用協調,工作流程、GPU整合到CPU得好處

在不少人的心目中&#xff0c;顯卡最大的用途可能就只有兩點——玩游戲、看電影&#xff0c;除此之外&#xff0c;GPU并沒有其他的作用了。但是隨著微軟IE9的正式發布&#xff0c;不少人突然發現&#xff0c;微軟一直提到一個名詞&#xff1a;GPU硬件加速&#xff0c;從而也讓不…

[luoguP1029] 最大公約數和最小公倍數問題(數論)

傳送門 一.暴力枚舉&#xff08;加了點優化&#xff09; #include <cstdio>int x, y, ans;inline int gcd(int x, int y) {return !y ? x : gcd(y, x % y); }inline int lcm(int x, int y) {return x / gcd(x, y) * y; }int main() {int i, j;scanf("%d %d", …

CPU和GPU擅長和不擅長的方面

從它們執行運算的速度與效率的方面來探討這個論題。CPU和GPU都是具有運算能力的芯片&#xff0c; CPU更像“通才”——指令運算(執行)為重數值運算&#xff0c; GPU更像“專才”——圖形類數值計算為核心。在不同類型的運算方面的速度也就決定了它們的能力——“擅長和不擅長”…

一些IO流的知識

IO流&#xff1a; 輸入流&#xff1a;輸出流&#xff1a; 字節流&#xff1a;字符流&#xff1a;為了處理文字數據方便而出現的對象。 其實這些對象的內部使用的還是字節流(因為文字最終也是字節數據) 只不過&#xff0c;通過字節流讀取了相對應的字節數&#xff0c;沒有對這些…

為人示弱,做事留余 | 摸魚系列

我很喜歡結交有很好的自然觀察能力的朋友&#xff0c;這是種對周圍環境和文化的洞察力。 一方面的原因是優秀的領導者、企業家和投資人能利用這種能力發現新市場&#xff0c;預測新潮流&#xff0c;設計出有效的市場營銷活動&#xff0c;并找到需要重點關注的人群。 另一方面&a…