js實現字符串去重和數組去重


https://blog.csdn.net/charles_tian/article/details/79938010

題目:實現一個函數,去除輸入字符串中的重復字符。

題目:實現一個函數,去除輸入數組中重復的元素。

我想這道題是大家經常遇見的吧,是不是好像每次遇到的時候又變的不會了?那是因為不夠專注,當初學習的時候知識初淺的看了看答案的思路便不再關注了,這肯定不行,要想在程序員的道路上走的更遠,必須得明白解這道題的原理和做法,用了哪些你不知道的方法,甚至是還要比較哪個方法更優,明白更優的這個方法的原理出自哪里,這樣才能越走越遠。

對於這樣的題,網上已經有很多的答案了,這里我只是做個總結,多數部分屬於轉載,但是希望大家堅持看完,因為要着重理解思路和邏輯,這樣才對大家有所幫助。

1)字符串去重

1.for遍歷

主要思路:首先新建一個空的字符串,然后聲明一個flag作為下文的條件判斷,隨后就開始for循環輸入的字符串,在for循環里面給flag賦值為1,然后在for循環又for循環一次,里面的循環是循環新字符串里的字符,然后給出判斷,如果相同,flag=0,且跳出循環,最后對flag進行判斷,如果為1,表示循環的字符在新字符串里沒有出現過,那么就將該字符添加到新字符串中;如果為0,則不進行處理,直接跳過,最后返回新字符串的值。

該方法不是很推薦,因為執行了兩次遍歷,比較消耗性能,大家也可以通過測試數據得知,這個方法相對來說比較耗時。

代碼實現如下:

function removeRepeatStr(str){
var newStr = '';
var flag;
var len = str.length;
for(var i=0; i<len; i++){
flag = 1;
var newLen = newStr.length;
for(var j=0; j<newLen; j++){
if(str[i] == newStr[j]){
flag = 0;
break;
}
}
if(flag){
newStr = newStr + str[i];
}
}
return newStr;
}
2)indexOf方法(無兼容問題)

主要思路:也是要新建一個空的字符串,然后用遍歷的形式遍歷輸入的字符串,然后判斷遍歷的字符在新的字符串中是否是第一次出現,如果是,則添加到空的字符串中;如果不是,則跳過,返回-1。最后返回新的字符串。

該方法本質上來說跟第一種沒有太大的區別,只不過判斷的條件變成了是否是第一次出現,而由於indexOf這個方法本質上也是通過遍歷字符串的形式查找某個字符在字符串中第一次出現的位置,如果沒有在字符串中找到,則返回-1。所以該方法也不是太推薦,因為也是比較耗性能。不如直接查找字符索引值來的快。

代碼實現如下:

function removeRepeatStr(str){
var newStr = '';
var len = str.length;
for(var i=0; i<len; i++){
if(newStr.indexOf(str[i])==-1){
newStr = newStr + str[i];
}
}
return newStr;
}
3)search方法

主要思路:與第二種方法一致,只不過換了一種檢測方法。即將indexOf方法變成了search方法,indexOf方法我們知道是,遍歷字符串的形式查找某個字符在字符串中第一次出現的位置,如果沒有在字符串中找到,則返回-1;而search方法是這樣的,用於檢索字符串中指定的子字符串,或檢索與正則表達式相匹配的子字符串。如果沒有找到任何匹配的子串,則返回 -1。

這個方法相對第二種來說,好了一點點,但是僅此一點點。

代碼實現如下:

function removeRepeatStr(str){
var newStr = '';
var len = str.length;
for(var i=0; i<len; i++){
if(newStr.search(str[i])==-1){
newStr = newStr + str[i];
}
}
return newStr;
}
4)對象屬性

主要思路:新建一個空的對象和一個空的字符串,遍歷輸入的字符串,將遍歷到的字符作為對象的屬性並賦值為1,然后通過對象屬性值來判斷數組元素是否重復(亦即每次遍歷arr的元素,這里需要說明的是,此時並沒有把這個元素存入至對象中,是先將其作為對象屬性判斷當前對象中是否已經存在了這個屬性),如果不是,則添加到新的字符串中;如果是,則跳過。最后返回新的字符串。

這里為了更好的理解,我着重解釋兩個地方,也是相對難以理解的地方。

第一個:判斷代碼,if( !obj[str[i]] ){},剛才我也解釋了,這里判斷的條件是對象屬性的值,str[i]是對象屬性,如果對象屬性的值存在,那么便說明這個屬性已經在對象中存在了;沒有值,則把當前的字符存進字符串中;

第二個:賦值代碼,obj[str[i]],這個是為了保證對象屬性有值,如果不賦值,那個這個對象屬性的值默認為undefined;

接下來是聯合理解:在遍歷第一個字符時,對象初始又為空,所以當第一個字符作為對象屬性的時候,它是沒有值的,沒有值的話就默認為undefined,亦即obj[str[0]] == undefined,在判斷語句中,undefined會被轉為false,如果轉化為數字型,則為0;亦即在判斷語句中obj[str[0]] == fasle,所以if( !obj[str[0]] ) == if( true ),所以會執行下面的語句,也就是把第一個字符存進字符串中,並給obj[ str[0] ]賦值,如果不賦值,相當於還是undefined,等到遍歷到重復的元素時,根本不會跳過,還是會存進字符串中,這就起不到去重的效果了。如果賦值了,obj[str[0]] = 1,在判斷語句中就將值轉化為true(這里不懂為什么要轉為true的話,那你得回去好好看書了),而前面又有一個非號,那么判斷語句的結果就是false,就不會執行下面的語句了,就實現了跳過的操作,也就達到了去重的效果。

這個方法比上述幾個方法好一些,畢竟在對象里面找屬性值,只要匹配到屬性名就可以了,不用全部遍歷,節省時間。

代碼實現如下:

function removeRepeatStr(str){
var obj = {};
var newStr = '';
var len = str.length;
for(var i=0; i<len; i++){
if(!obj[str[i]]){
newStr = newStr + str[i];
obj[str[i]] = 1;//注意,這里的1是給對象屬性賦值,這個值可以任意取。意思是把每個遍歷的字符作為對象屬性並賦值保存,保證該屬性的唯一性
}
}
return newStr;
}
2)數組去重

1.indexOf方法

主要思路:跟上面字符串去重類似。新建一個空的數組,然后遍歷傳入的數組,如果新的數組里沒有遍歷的元素,那么就加入到新建的數組內;如果有,則跳過。最后返回新建的數組,這個數組就是不含重復元素的數組。

跟之前分析字符串類似,該方法也比較耗時和浪費資源。

代碼實現如下:

function removeRepeatArrElement(arr){
var newArr = [];
var len = arr.length;
for(var i=0; i<len; i++){
if(newArr.indexOf(arr[i])==-1){
newArr.push(arr[i]);
}
}
return newArr;
}
2.對象屬性

主要思路:跟字符串去重類似,這里不再贅述。反正比雙重for循環和indexOf方法要好。

代碼實現如下:

function removeRepeatArrElement(arr){
var obj = {};
var newArr = [];
var len = arr.length;
for(var i=0; i<len; i++){
if(!obj[arr[i]]){//這里也可以通過對對象的屬性是否存在進行判斷,即if(!obj.hasOwnProperty(arr[i]))
newArr.push(arr[i]);
obj[arr[i]] = true;
}
}
return newArr;
}
3.for循環

主要思路:就是將數組逐個搬到另一個數組中去,當遇到重復元素時,不移動;若不重復則移動到新的數組中。

這個方法不推薦,因為它使用的是雙重for循環,性能消耗較大,因為在遍歷i時,又在i里面遍歷j,比如i和j各取10,那么遍歷的總次數為100次,即當i=0時,j分別取1,2,3,4,5,6,7,8,9,10,然后當i=1時,j又去分別取這10個值,直到i=10,j=10才結束,相當耗性能和時間。而這里是對第一個元素匹配的時候,查找其后面的元素是否與其重復,即當i=0時,j取1-9;當i=1時,j取2-9...;當i=8時,j取9;當i=9時,j取不到值,為undefined,故判斷為false,直接輸出第索引值為9(第十個元素)的元素。

代碼實現如下:

function removeRepeatArrElement(arr){
var newArr = [];
var len = arr.length;
var flag;
for(var i=0; i<len; i++){
flag = true;
for(var j=i; j<len-1; j++){
if(arr[i] == arr[j+1]){
flag = false;
break;
}
}
if(flag){
newArr.push(arr[i]);
}
}
return newArr;
}
 

4.value -> key方法

主要思路:顧名思義,就是將數組的值賦值給另一個數組的鍵,此時重復的元素都被刪除,然后取新數組的鍵作為去重后的結果

代碼實現如下:

function removeRepeatArrElement(arr){
var newArr = [];
var temp = [];
for(var i in temp){
temp[arr[i]] = 1;
}
for(var i in temp){
newArr.push(i);
}
return newArr;
}
但是這個方法有一點需要注意,就是輸出數組里的元素是以字符串的形式給出的,而不是number類型或者其他類型。所以后面要想得到自己想要的數據類型,那么后期還要進一步處理。

 

5.sort()方法

主要思路:首先將數組進行排序,排序了之后我們都知道,相同的元素會在一起,然后進行循環,依次對比相鄰的兩個元素是否相同,若相同,則跳過;若不同,則加入到新建的數組中。

代碼實現如下:

function removeRepeatArrElement(arr){
var newArray = arr.sort();
var newArr = [];
var len = newArray.length;
for(var i=0; i<len; i++){
if(newArray[i] != newArray[i+1]){
newArr.push([newArray[i]]);
}
}
}
return newArr;
}
console.log(removeRepeatArrElement([12,4,3,5,6,23,4,5,6]));//[ 12, 23, 3, 4, 5, 6 ]
下面一行是我測試用的,大家可以看到重復的數字已經去除了,然后輸出[ 12, 23, 3, 4, 5, 6 ]。

但是這里我產生了一個疑惑:sort()方法括號不帶函數默認是升序排列輸出(是按照字符編碼順序輸出的),所以現在輸出的卻是[ 12, 23, 3, 4, 5, 6 ],而不是[ 3, 4, 5, 6 , 12, 23 ]。

如果感興趣的同學可以了解其他的原生j排序s實現代碼,可以參考以下鏈接:js排序算法和js原生排序算法。

最后還要提到的一點就是,不知道有沒有同學有疑問,為什么在去重方法中,對象屬性方法中的判斷對象屬性值的時候,對象取屬性的時候用的是中括號,而不是點方法?

因為點語法和中括號法還是有區別的:

1、中括號法可以用變量作為屬性名,而點方法不可以;

2、中括號法可以用數字作為屬性名,而點語法不可以;

3、中括號法可以使用js的關鍵字和保留字作為屬性名,而點語法不可以(盡量避免在變量或者屬性中使用關鍵字或保留字);

所以為了保證能取到對象里的屬性,用中括號法比較實際。

6.ES6新特性:set數據結構

基本用法:ES6 提供了新的數據結構 Set。它類似於數組,但是成員的值都是唯一的,沒有重復的值。

Set 本身是一個構造函數,用來生成 Set 數據結構。

調用:

const set = new Set([1, 2, 3, 4, 4]);
console.log(set)//[1,2,3,4]
是不是特別的方便,所以說,還是盡快學習ES6吧~
---------------------

轉載於:https://www.cnblogs.com/liangyh55/p/11334645.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM