簡體   English   中英

從 Javascript/jQuery 中的數組中刪除多個元素

[英]Remove multiple elements from array in Javascript/jQuery

我有兩個數組。 第一個數組包含一些值,而第二個數組包含應該從第一個數組中刪除的值的索引。 例如:

var valuesArr = new Array("v1","v2","v3","v4","v5");   
var removeValFromIndex = new Array(0,2,4);

我想從valuesArr中刪除索引0,2,4處存在的值。 我認為本機splice方法可能會有所幫助,所以我想出了:

$.each(removeValFromIndex,function(index,value){
    valuesArr.splice(value,1);
});

但它不起作用,因為在每次splice之后, valuesArr中的值的索引都不同。 我可以通過使用臨時數組並將所有值復制到第二個數組來解決這個問題,但我想知道是否有任何本機方法可以傳遞多個索引來從數組中刪除值。

我更喜歡 jQuery 解決方案。 (不確定我是否可以在這里使用grep

總是有普通的舊for循環:

var valuesArr = ["v1","v2","v3","v4","v5"],
    removeValFromIndex = [0,2,4];    

for (var i = removeValFromIndex.length -1; i >= 0; i--)
   valuesArr.splice(removeValFromIndex[i],1);

以相反的順序遍歷removeValFromIndex ,您可以.splice()而不會弄亂尚未刪除的項目的索引。

請注意,在上面我使用了帶有方括號的數組文字語法來聲明兩個數組。 這是推薦的語法,因為new Array()的使用可能會令人困惑,因為它的響應取決於您傳入的參數數量。

編輯:剛剛看到您對關於索引數組不一定按任何特定順序的另一個答案的評論。 如果是這種情況,只需在開始之前將其按降序排序:

removeValFromIndex.sort(function(a,b){ return b - a; });

並按照您喜歡的任何循環 / $.each() / 等方法進行。

我建議你使用Array.prototype.filter

var valuesArr = ["v1","v2","v3","v4","v5"];
var removeValFrom = [0, 2, 4];
valuesArr = valuesArr.filter(function(value, index) {
     return removeValFrom.indexOf(index) == -1;
})

這是我在不使用 lodash/underscore 時使用的一個:

while(IndexesToBeRemoved.length) {
    elements.splice(IndexesToBeRemoved.pop(), 1);
}

不是in-place ,但可以使用jQuerygrepinArray函數來完成。

var arr = $.grep(valuesArr, function(n, i) {
    return $.inArray(i, removeValFromIndex) ==-1;
});

alert(arr);//arr contains V2, V4

檢查這個小提琴。

使用filterSet的簡單高效(線性復雜度)解決方案:

 const valuesArr = ['v1', 'v2', 'v3', 'v4', 'v5']; const removeValFromIndex = [0, 2, 4]; const indexSet = new Set(removeValFromIndex); const arrayWithValuesRemoved = valuesArr.filter((value, i) => !indexSet.has(i)); console.log(arrayWithValuesRemoved);

該實現的最大優點是 Set 查找操作 ( has函數) 需要一個恆定的時間,例如比 nevace 的答案更快。

這對我很有效,並且在從對象數組中刪除時也有效:

var array = [ 
    { id: 1, name: 'bob', faveColor: 'blue' }, 
    { id: 2, name: 'jane', faveColor: 'red' }, 
    { id: 3, name: 'sam', faveColor: 'blue' }
];

// remove people that like blue

array.filter(x => x.faveColor === 'blue').forEach(x => array.splice(array.indexOf(x), 1));

可能有一種更短更有效的方法來編寫它,但這確實有效。

感覺有必要用O(n)時間發布答案:)。 拼接解決方案的問題在於,由於 array 的底層實現實際上是一個 array ,每個splice調用將花費O(n)時間。 當我們設置一個示例來利用此行為時,這一點最為明顯:

var n = 100
var xs = []
for(var i=0; i<n;i++)
  xs.push(i)
var is = []
for(var i=n/2-1; i>=0;i--)
  is.push(i)

這會刪除從中間到開始的元素,因此每次刪除都會強制 js 引擎復制n/2元素,我們總共有(n/2)^2復制操作,這是二次的。

拼接解決方案(假設is已經按降序排序以消除開銷)如下所示:

for(var i=0; i<is.length; i++)
  xs.splice(is[i], 1)

然而,實現線性時間解決方案並不難,通過從頭開始重新構造數組,使用掩碼查看我們是否復制元素(排序會將其推送到O(n)log(n) )。 以下是這樣一個實現(不是為了速度而將mask反轉為布爾值):

var mask = new Array(xs.length)
for(var i=is.length - 1; i>=0; i--)
  mask[is[i]] = true
var offset = 0
for(var i=0; i<xs.length; i++){
  if(mask[i] === undefined){
    xs[offset] = xs[i]
    offset++
  }
}
xs.length = offset

我在jsperf.com上運行了這個,即使n=100 ,拼接方法也慢了 90%。 對於較大的n ,這種差異會更大。

function filtermethod(element, index, array) {  
    return removeValFromIndex.find(index)
}  
var result = valuesArr.filter(filtermethod);

MDN 參考在這里

在純 JS 中,您可以向后循環數組,因此splice()不會弄亂循環中下一個元素的索引:

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

使用 ES5 的簡單解決方案。 這似乎更適合現在的大多數應用程序,因為許多應用程序不再想依賴 jQuery 等。

當要刪除的索引按升序排序時:

var valuesArr = ["v1", "v2", "v3", "v4", "v5"];   
var removeValFromIndex = [0, 2, 4]; // ascending

removeValFromIndex.reverse().forEach(function(index) {
  valuesArr.splice(index, 1);
});

當要刪除的索引沒有排序時:

var valuesArr = ["v1", "v2", "v3", "v4", "v5"];   
var removeValFromIndex = [2, 4, 0];  // unsorted

removeValFromIndex.sort(function(a, b) { return b - a; }).forEach(function(index) {
  valuesArr.splice(index, 1);
});

快速 ES6 一班:

const valuesArr = new Array("v1","v2","v3","v4","v5");   
const removeValFromIndex = new Array(0,2,4);

const arrayWithValuesRemoved = valuesArr.filter((value, i) => removeValFromIndex.includes(i))

如果你使用underscore.js ,你可以使用_.filter()來解決你的問題。

var valuesArr = new Array("v1","v2","v3","v4","v5");
var removeValFromIndex = new Array(0,2,4);
var filteredArr = _.filter(valuesArr, function(item, index){
                  return !_.contains(removeValFromIndex, index);
                });

此外,如果您嘗試使用項目列表而不是索引來刪除項目,則可以簡單地使用_.without() ,如下所示:

var valuesArr = new Array("v1","v2","v3","v4","v5");
var filteredArr = _.without(valuesArr, "V1", "V3");

現在filteredArr應該是["V2", "V4", "V5"]

我發現這是最優雅的解決方案:

const oldArray = [1, 2, 3, 4, 5]
const removeItems = [1, 3, 5]

const newArray = oldArray.filter((value) => {
    return !removeItems.includes(value)
})

console.log(newArray)

輸出:

[2, 4]

這是一種可能性:

valuesArr = removeValFromIndex.reduceRight(function (arr, it) {
    arr.splice(it, 1);
    return arr;
}, valuesArr.sort(function (a, b) { return b - a }));

jsFiddle 上的示例

Array.prototype.reduceRight 上的 MDN

過濾器+ indexOf (IE9+):

function removeMany(array, indexes) {
  return array.filter(function(_, idx) {
    return indexes.indexOf(idx) === -1;
  });
}); 

或者使用 ES6 過濾器+ 查找(Edge+):

function removeMany(array, indexes = []) {
  return array.filter((_, idx) => indexes.indexOf(idx) === -1)
}

這是一個快速的。

function removeFromArray(arr, toRemove){
    return arr.filter(item => toRemove.indexOf(item) === -1)
}

const arr1 = [1, 2, 3, 4, 5, 6, 7]
const arr2 = removeFromArray(arr1, [2, 4, 6]) // [1,3,5,7]

您可以通過將removeValFromIndex替換為removeValFromIndex.reverse()來更正您的代碼。 如果該數組不能保證使用升序,您可以改用removeValFromIndex.sort(function(a, b) { return b - a })

var valuesArr = new Array("v1","v2","v3","v4","v5");   
var removeValFromIndex = new Array(0,2,4);

console.log(valuesArr)
let arr2 = [];

for (let i = 0; i < valuesArr.length; i++){
  if (    //could also just imput this below instead of index value
    valuesArr[i] !== valuesArr[0] && // "v1" <--
    valuesArr[i] !== valuesArr[2] && // "v3" <--
    valuesArr[i] !== valuesArr[4]    // "v5" <--
  ){
    arr2.push(valuesArr[i]);
  }
}

console.log(arr2);

這行得通。 但是,您將在此過程中創建一個新數組。 不確定您是否想要,但從技術上講,它將是一個僅包含您想要的值的數組。

您可以嘗試 Lodash js 庫函數( _.forEach()_.remove() )。 我正在使用這種技術從表中刪除多行。

let valuesArr = [
    {id: 1, name: "dog"}, 
    {id: 2, name: "cat"}, 
    {id: 3, name: "rat"}, 
    {id: 4, name: "bat"},
    {id: 5, name: "pig"},
]; 
let removeValFromIndex = [
    {id: 2, name: "cat"}, 
    {id: 5, name: "pig"},
]; 
_.forEach(removeValFromIndex, (indi) => {
    _.remove(valuesArr, (item) => {
        return item.id === indi.id;
    });
})
console.log(valuesArr)
/*[
    {id: 1, name: "dog"},  
    {id: 3, name: "rat"}, 
    {id: 4, name: "bat"},
];*/ 

在改變數組之前不要忘記克隆( _.clone(valuesArr)[...valuesArr]

嘗試這個

 var valuesArr = new Array("v1", "v2", "v3", "v4", "v5"); console.info("Before valuesArr = " + valuesArr); var removeValFromIndex = new Array(0, 2, 4); valuesArr = valuesArr.filter((val, index) => { return !removeValFromIndex.includes(index); }) console.info("After valuesArr = " + valuesArr);

聽起來像Apply可能是您正在尋找的東西。
也許這樣的事情會起作用?

Array.prototype.splice.apply(valuesArray, removeValFromIndexes );
removeValFromIndex.forEach(function(toRemoveIndex){
    valuesArr.splice(toRemoveIndex,1);
});

您可以使用foreach循環來執行此操作。

var valuesArr = new Array("v1","v2","v3","v4","v5");   
var removeValFromIndex = new Array(0,2,4);

removeValFromIndex.forEach((value, index)=>{
    valuesArr.splice(value, 1);
});

console.log(valuesArr);

另一種方法是您可以使用過濾器

let arr = [ 2, 3, 5, 8, 4 ];
let values = [ 2, 4 ];
 
arr = arr.filter(item => !values.includes(item));
console.log(arr);

您可以嘗試使用delete array[index]這不會完全刪除元素,而是將值設置為undefined

對於多個項目或唯一項目:

我建議你使用Array.prototype.filter

如果您已經知道索引,則永遠不要使用 indexOf!:

var valuesArr = ["v1","v2","v3","v4","v5"];
var removeValFrom = [0, 2, 4];

valuesArr = valuesArr.filter(function(value, index) {
     return removeValFrom.indexOf(index) == -1;
}); // BIG O(N*m) where N is length of valuesArr and m is length removeValFrom

做:

使用哈希...使用Array.prototype.map

  var valuesArr = ["v1","v2","v3","v4","v5"];
  var removeValFrom = {};
  ([0, 2, 4]).map(x=>removeValFrom[x]=1); //bild the hash.
  valuesArr = valuesArr.filter(function(value, index) {
      return removeValFrom[index] == 1;
  }); // BIG O(N) where N is valuesArr;

您可以從數組構造一個Set ,然后從該集合創建一個數組。

const array = [1, 1, 2, 3, 5, 5, 1];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // Result: [1, 2, 3, 5]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM