简体   繁体   English

从 Javascript/jQuery 中的数组中删除多个元素

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

I have two arrays.我有两个数组。 The first array contains some values while the second array contains indices of the values which should be removed from the first array.第一个数组包含一些值,而第二个数组包含应该从第一个数组中删除的值的索引。 For example:例如:

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

I want to remove the values present at indices 0,2,4 from valuesArr .我想从valuesArr中删除索引0,2,4处存在的值。 I thought the native splice method might help so I came up with:我认为本机splice方法可能会有所帮助,所以我想出了:

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

But it didn't work because after each splice , the indices of the values in valuesArr were different.但它不起作用,因为在每次splice之后, valuesArr中的值的索引都不同。 I could solve this problem by using a temporary array and copying all values to the second array, but I was wondering if there are any native methods to which we can pass multiple indices at which to remove values from an array.我可以通过使用临时数组并将所有值复制到第二个数组来解决这个问题,但我想知道是否有任何本机方法可以传递多个索引来从数组中删除值。

I would prefer a jQuery solution.我更喜欢 jQuery 解决方案。 (Not sure if I can use grep here) (不确定我是否可以在这里使用grep

There's always the plain old for loop:总是有普通的旧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);

Go through removeValFromIndex in reverse order and you can .splice() without messing up the indexes of the yet-to-be-removed items.以相反的顺序遍历removeValFromIndex ,您可以.splice()而不会弄乱尚未删除的项目的索引。

Note in the above I've used the array-literal syntax with square brackets to declare the two arrays.请注意,在上面我使用了带有方括号的数组文字语法来声明两个数组。 This is the recommended syntax because new Array() use is potentially confusing given that it responds differently depending on how many parameters you pass in.这是推荐的语法,因为new Array()的使用可能会令人困惑,因为它的响应取决于您传入的参数数量。

EDIT : Just saw your comment on another answer about the array of indexes not necessarily being in any particular order.编辑:刚刚看到您对关于索引数组不一定按任何特定顺序的另一个答案的评论。 If that's the case just sort it into descending order before you start:如果是这种情况,只需在开始之前将其按降序排序:

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

And follow that with whatever looping / $.each() / etc. method you like.并按照您喜欢的任何循环 / $.each() / 等方法进行。

I suggest you use Array.prototype.filter我建议你使用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;
})

Here is one that I use when not going with lodash/underscore:这是我在不使用 lodash/underscore 时使用的一个:

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

Not in-place but can be done using grep and inArray functions of jQuery .不是in-place ,但可以使用jQuerygrepinArray函数来完成。

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

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

check this fiddle.检查这个小提琴。

A simple and efficient (linear complexity) solution using filter and Set :使用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);

The great advantage of that implementation is that the Set lookup operation ( has function) takes a constant time, being faster than nevace's answer, for example.该实现的最大优点是 Set 查找操作 ( has函数) 需要一个恒定的时间,例如比 nevace 的答案更快。

This works well for me and work when deleting from an array of objects too:这对我很有效,并且在从对象数组中删除时也有效:

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));

There might be a shorter more effecient way to write this but this does work.可能有一种更短更有效的方法来编写它,但这确实有效。

It feels necessary to post an answer with O(n) time :).感觉有必要用O(n)时间发布答案:)。 The problem with the splice solution is that due to the underlying implementation of array being literally an array , each splice call will take O(n) time.拼接解决方案的问题在于,由于 array 的底层实现实际上是一个 array ,每个splice调用将花费O(n)时间。 This is most pronounced when we setup an example to exploit this behavior:当我们设置一个示例来利用此行为时,这一点最为明显:

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)

This removes elements starting from the middle to the start, hence each remove forces the js engine to copy n/2 elements, we have (n/2)^2 copy operations in total which is quadratic.这会删除从中间到开始的元素,因此每次删除都会强制 js 引擎复制n/2元素,我们总共有(n/2)^2复制操作,这是二次的。

The splice solution (assuming is is already sorted in decreasing order to get rid of overheads) goes like this:拼接解决方案(假设is已经按降序排序以消除开销)如下所示:

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

However, it is not hard to implement a linear time solution, by re-constructing the array from scratch, using a mask to see if we copy elements or not (sort will push this to O(n)log(n) ).然而,实现线性时间解决方案并不难,通过从头开始重新构造数组,使用掩码查看我们是否复制元素(排序会将其推送到O(n)log(n) )。 The following is such an implementation (not that mask is boolean inverted for speed):以下是这样一个实现(不是为了速度而将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

I ran this on jsperf.com and for even n=100 the splice method is a full 90% slower.我在jsperf.com上运行了这个,即使n=100 ,拼接方法也慢了 90%。 For larger n this difference will be much greater.对于较大的n ,这种差异会更大。

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

MDN reference is here MDN 参考在这里

In pure JS you can loop through the array backwards, so splice() will not mess up indices of the elements next in the loop:在纯 JS 中,您可以向后循环数组,因此splice()不会弄乱循环中下一个元素的索引:

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

A simple solution using ES5.使用 ES5 的简单解决方案。 This seems more appropriate for most applications nowadays, since many do no longer want to rely on jQuery etc.这似乎更适合现在的大多数应用程序,因为许多应用程序不再想依赖 jQuery 等。

When the indexes to be removed are sorted in ascending order:当要删除的索引按升序排序时:

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

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

When the indexes to be removed are not sorted:当要删除的索引没有排序时:

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);
});

Quick ES6 one liner:快速 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))

If you are using underscore.js , you can use _.filter() to solve your problem.如果你使用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);
                });

Additionally, if you are trying to remove items using a list of items instead of indexes, you can simply use _.without() , like so:此外,如果您尝试使用项目列表而不是索引来删除项目,则可以简单地使用_.without() ,如下所示:

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

Now filteredArr should be ["V2", "V4", "V5"]现在filteredArr应该是["V2", "V4", "V5"]

I find this the most elegant solution:我发现这是最优雅的解决方案:

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

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

console.log(newArray)

output:输出:

[2, 4]

Here's one possibility:这是一种可能性:

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

Example on jsFiddle jsFiddle 上的示例

MDN on Array.prototype.reduceRight Array.prototype.reduceRight 上的 MDN

filter + indexOf (IE9+): 过滤器+ indexOf (IE9+):

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

Or with ES6 filter + find (Edge+):或者使用 ES6 过滤器+ 查找(Edge+):

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

Here's a quickie.这是一个快速的。

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]

You can correct your code by replacing removeValFromIndex with removeValFromIndex.reverse() .您可以通过将removeValFromIndex替换为removeValFromIndex.reverse()来更正您的代码。 If that array is not guaranteed to use ascending order, you can instead use removeValFromIndex.sort(function(a, b) { return b - a }) .如果该数组不能保证使用升序,您可以改用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);

This works.这行得通。 However, you would make a new array in the process.但是,您将在此过程中创建一个新数组。 Not sure if thats would you want or not, but technically it would be an array containing only the values you wanted.不确定您是否想要,但从技术上讲,它将是一个仅包含您想要的值的数组。

You can try Lodash js library functions ( _.forEach() , _.remove() ).您可以尝试 Lodash js 库函数( _.forEach()_.remove() )。 I was using this technique to remove multiple rows from the table.我正在使用这种技术从表中删除多行。

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"},
];*/ 

Don't forget to clone ( _.clone(valuesArr) or [...valuesArr] ) before mutate your array在改变数组之前不要忘记克隆( _.clone(valuesArr)[...valuesArr]

Try this尝试这个

 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);

Sounds like Apply could be what you are looking for.听起来像Apply可能是您正在寻找的东西。
maybe something like this would work?也许这样的事情会起作用?

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

You can use foreach loop to do so.您可以使用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);

Another way is You can use the filter另一种方法是您可以使用过滤器

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

For Multiple items or unique item:对于多个项目或唯一项目:

I suggest you use Array.prototype.filter我建议你使用Array.prototype.filter

Don't ever use indexOf if you already know the index!:如果您已经知道索引,则永远不要使用 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

Do:做:

with Hashes... using Array.prototype.map使用哈希...使用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;

You could construct a Set from the array and then create an array from the set.您可以从数组构造一个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