2013-12-22 44 views
11

我想使用函數刪除數組中出現多次的元素。循環移除多次出現的數組中的元素

var array=["hello","hello","world",1,"world"]; 

function removeItem(item){ 
    for(i in array){ 
     if(array[i]==item) array.splice(i,1); 
    } 
} 
removeItem("world"); 
//Return hello,hello,1 
removeItem("hello"); 
//Return hello,world,1,world 

該循環時,它在序列重複兩次不會刪除該元素,只刪除其中之一。

爲什麼?

+0

請問這項工作atall?變量我不會等於數組的索引,只是變量數組 –

回答

20

您有一個內置函數filter,它根據謂詞(條件)過濾數組。

它不會改變原始數組,但會返回一個新的過濾數組。

var array=["hello","hello","world",1,"world"]; 
var filtered = array.filter(function(element) { 
    return element !== "hello"; 
}); // filtered contains no occurrences of hello 

您可以將其解壓縮到一個功能:

function without(array, what){ 
    return array.filter(function(element){ 
     return element !== what; 
    }); 
} 

然而,原始過濾器似乎很傳神。

Here is a link to its documentation

你原有的功能有幾個問題:

  • 它重複使用for... in循環具有迭代順序上沒有保證的陣列。另外,don't use it to iterate through arrays - 更喜歡正常的for...循環或.forEach
  • 你正在迭代一個錯誤的數組,因此你跳過了下一個項目,因爲你既是刪除元素和進展數組。
+1

的成員,但是這會創建一個新的數組?不要編輯原始數組 –

+1

@EduenSarceno是的,你總是可以做'array = array.filter'並將它分配給它 - 這完全沒問題。通常你想要一個副本。 –

+0

謝謝!我在js –

8

這是因爲for -loop在發生被刪除後轉到下一個項目,從而直接跳過該項目之後的項目。

例如,讓我們假定需要item1此數組中的要被刪除(注意<-是循環的指數):

item1 (<-), item2, item3 

刪除後:

item2 (<-), item3 

和後指數是更新(作爲循環完成)

item2, item3 (<-) 

所以你可以看到item2被跳過,因此沒有被檢查!

因此你需要通過手動1降低指數來彌補這一點,如下所示:

function removeItem(item){ 
    for(var i = 0; i < array.length; i++){ 
     if(array[i]==item) { 
      array.splice(i,1); 
      i--; // Prevent skipping an item 
     } 
    } 
} 

不要使用此for -loop的,你可以使用更多的「現代」的方法來filterother answer by Benjamin中顯示不需要的項目。

+0

的noob謝謝你的解釋,循環減少不會跳過其他項目。謝謝! –

0

嘗試運行您的代碼「手動」 - 「你好」是彼此關注。你刪除第一個,你的數組在一個項目中收縮,現在你有下一個項目的索引。

去除 「你好」,」 開始循環。I = 0,陣列= [ 「你好」, 「你好」, 「世界」,1, 「世界」] i被指向 「你好」 除去第一項, i = 0 array = [「hello」,「world」,1,「world」] next loop,i = 1,array = [「hello」,「world」,1,「world」]。將不會被刪除

讓我們看看「世界」= i = 2,指向「世界」(刪除)。在下一個循環陣列是: [「hello」,「hello」,1, 「世界」]和i = 3,這裏是第二個「世界」

你想要發生什麼?你想刪除我的所有實例TEM?或只有第一個?對於第一種情況,刪除應該在

while (array[i] == item) array.splice(i,1); 

第二種情況 - 只要您刪除項目就立即返回。

0

創建給出一個數組集,修改原始數組

Demo on Fiddle

var array=["hello","hello","world",1,"world"]; 

    function removeDups(items) { 
     var i, 
      setObj = {}, 
      setArray = []; 
     for (i = 0; i < items.length; i += 1) { 
      if (!setObj.hasOwnProperty(items[i])) { 
       setArray.push(items[i]); 
       setObj[items[i]] = true; 
      } 
     } 
     return setArray; 
    } 

    console.log(removeDups(array)); // ["hello", "world", 1] 
0

我必須說,我的方法不使用的splice功能,你需要另一個數組這個解決方案好。我想你的循環數組的方式不對。您正在使用for in循環用於對象,而不是數組。如果您使用的是jQuery,則最好使用$.each,如果您使用的是vanila Javascript,則最好使用Array.prototype.forEach

其次,爲什麼不創建一個新的空數組,通過它循環和只添加到新數組的獨特元素,像這樣:

第一種方法(jQuery的)

var newArray = []; 
$.each(array, function(i, element) { 
     if ($.inArray(element, newArray) === -1) { 
      newArray.push(region); 
     } 
}); 

第二種方法(Vanila JavaScript)的

var newArray = []; 
array.forEach(function(i, element) { 
    if (newArray.indexOf(element) === -1) { 
      newArray.push(region); 
    } 
}); 
0

我需要一個斯萊的這件T的變化,能否從一個數組中刪除「N」項目的出現,讓我修改@ Veger的答案:

function removeArrayItemNTimes(arr,toRemove,times){ 
    times = times || 10; 
    for(var i = 0; i < arr.length; i++){ 
     if(arr[i]==toRemove) { 
      arr.splice(i,1); 
      i--; // Prevent skipping an item 
      times--; 
      if (times<=0) break; 
     } 
    } 
    return arr; 
} 
1

這些答案都不是很理想。過濾器接受的答案將導致數組的新實例。答案是第二多的票數,for循環在每個拼接上退一步,這是不必要的複雜。

如果您想要執行for循環循環方法,只需向下計數到0。

for (var i = array.length - 0; i >= 0; i--) { 
    if (array[i] === item) { 
    array.splice(i, 1); 
    } 
} 

但是,我用while循環和一個的indexOf出奇的快方法:

var itemIndex = 0; 
while ((itemIndex = valuesArray.indexOf(findItem, itemIndex)) > -1) { 
    valuesArray.splice(itemIndex, 1); 
} 

是什麼讓這個方法是不重複的是,拆卸下之後,下一個搜索將開始刪除項目之後的下一個元素的索引。這是因爲您可以將起始索引作爲第二個參數傳入indexOf

jsPerf test case比較上述兩種方法和接受濾波器的方法,所述常規indexOf完成第一上Firefox和鉻,和是第二上IE。 filter方法總是大幅放緩。

結論:反向循環有一段時間indexOf是目前我能找到的最好的方法來從數組中刪除同一元素的多個實例。使用過濾器會創建一個新數組,速度較慢,所以我會避免這種情況。

1

您可以使用loadash或在這種情況下 強調JS如果改編是可以通過刪除重複的數組:

var arr = [2,3,4,4,5,5]; 

arr = _.uniq(arr);