繁体   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