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

时间:2012-02-24 03:34:18

标签: javascript jquery

我有两个数组。第一个数组包含一些值,而第二个数组包含应从第一个数组中删除的值的索引。例如:

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

我想从0,2,4中移除索引valuesArr中的值。我认为原生的splice方法可能会有所帮助,所以我想出了:

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

但它不起作用,因为在每个splice之后,valuesArr中的值的索引是不同的。我可以通过使用临时数组并将所有值复制到第二个数组来解决这个问题,但我想知道是否有任何本机方法可以传递多个索引来从数组中删除值。

我更喜欢jQuery解决方案。 (不确定我是否可以在这里使用grep

24 个答案:

答案 0 :(得分:204)

总是存在普通的旧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()而不会弄乱尚未删除的项目的索引。

请注意,在上面我使用了带有方括号的array-literal语法来声明这两个数组。这是推荐的语法,因为new Array()使用可能会造成混淆,因为它会根据您传入的参数数量做出不同的响应。

编辑:刚刚看到你对另一个关于索引数组的答案的评论不一定是任何特定的顺序。如果是这种情况,只需在开始之前将其按降序排序:

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

然后按照您喜欢的循环/ $.each() /等方法进行操作。

答案 1 :(得分:18)

不是in-place,但可以使用grep的{​​{1}}和inArray函数完成。

jQuery

检查this小提琴。

答案 2 :(得分:18)

这是我在不使用lodash / underscore时使用的一个:

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

答案 3 :(得分:9)

我建议您使用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;
})

答案 4 :(得分:7)

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

MDN参考是here

答案 5 :(得分:6)

在纯JS中,你可以向后遍历数组,因此splice()不会弄乱循环中接下来元素的索引:

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

答案 6 :(得分:5)

有必要在O(n)时间:)发布答案。 splice解决方案的问题在于,由于数组的底层实现为literally an 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)

然而,实现线性时间解决方案并不难,通过从头开始重新构造数组,使用掩码来查看我们是否复制元素(sort会将其推送到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,这种差异会更大。

答案 7 :(得分:2)

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

答案 8 :(得分:2)

这对我来说很好,并且在从对象数组中删除时也可以工作:

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

也许可以写出一种更短,更有效的方法,但这确实有用。

答案 9 :(得分:1)

这是一种可能性:

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

Example on jsFiddle

MDN on Array.prototype.reduceRight

答案 10 :(得分:1)

如果您使用的是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"]

答案 11 :(得分:1)

filter + indexOf(IE9 +):

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

或使用ES6 filter + find(Edge +):

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

答案 12 :(得分:1)

您可以将removeValFromIndex替换为removeValFromIndex.reverse()来更正您的代码。如果不保证该数组使用升序,则可以使用removeValFromIndex.sort(function(a, b) { return b - a })

答案 13 :(得分: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]

答案 14 :(得分:0)

对于多个项目或唯一项目:

我建议您使用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;

答案 15 :(得分:0)

快速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))

答案 16 :(得分:0)

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

这有效。但是,您将在此过程中创建一个新阵列。不知道那是否是您想要的,但是从技术上讲,它将是一个仅包含您想要的值的数组。

答案 17 :(得分:0)

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

该实现的最大优点是,设置查找操作(has函数)需要固定的时间,例如比nevace的答案要快。

答案 18 :(得分:0)

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

答案 19 :(得分:0)

您可以尝试 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]

答案 20 :(得分:-1)

听起来Apply可能就是你要找的东西 也许像这样的东西会起作用吗?

Array.prototype.splice.apply(valuesArray, removeValFromIndexes );

答案 21 :(得分:-1)

您可以尝试使用delete array[index]这不会完全删除元素,而是将值设置为undefined

答案 22 :(得分:-1)

您可以从数组构造一个Set,然后从集合中创建一个数组。

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

答案 23 :(得分:-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);