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

xyz*_*xyz 97 javascript jquery

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

var valuesArr = new Array("v1","v2","v3","v4","v5");   
var removeValFromIndex = new Array(0,2,4);
Run Code Online (Sandbox Code Playgroud)

我想删除目前的指数值0,2,4valuesArr.我认为本机splice方法可能会有所帮助,所以我提出了:

$.each(removeValFromIndex,function(index,value){
    valuesArr.splice(value,1);
});
Run Code Online (Sandbox Code Playgroud)

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

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

nnn*_*nnn 224

总是有一个普通的旧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);
Run Code Online (Sandbox Code Playgroud)

经过removeValFromIndex按相反的顺序,你可以.splice()不会弄乱尚未要被移除的内容索引.

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

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

removeValFromIndex.sort(function(a,b){ return b - a; });
Run Code Online (Sandbox Code Playgroud)

无论$.each()你喜欢什么循环/ /等方法,都要遵循它.

  • @MuhammadUmer - 不,如果你做得不对,那就是我的答案所解释的. (5认同)
  • 感谢逆序认知. (4认同)
  • 不会切片弄乱索引 (3认同)
  • 仅当“removeValFromIndex”按升序排序时,这才有效 (3认同)
  • +1,我没有意识到我必须以相反的顺序进行拼接,虽然不是使用forEach,但我的方法是使用`$ .each(rvm.reverse(),function(e,i){})` (2认同)

Dan*_*ana 21

这是我不使用lodash /下划线时使用的一个:

while(IndexesToBeRemoved.length) {
    elements.splice(IndexesToBeRemoved.pop(), 1);
}
Run Code Online (Sandbox Code Playgroud)

  • 如果只有`IndexesToBeRemoved`数组按升序排序,则此解决方案有效. (8认同)
  • 太聪明了 (2认同)
  • 这些索引将在第一次拼接后失效。 (2认同)

The*_*iot 18

不是in-place可以使用grepinArray功能完成jQuery.

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

alert(arr);//arr contains V2, V4
Run Code Online (Sandbox Code Playgroud)

检查这个小提琴.


Саш*_*нко 16

我建议你使用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;
})
Run Code Online (Sandbox Code Playgroud)

  • 投票。根据 https://jsperf.com/remove-multiple/1,比拼接方法更快 (3认同)

Alb*_*res 11

使用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);
Run Code Online (Sandbox Code Playgroud)

该实现的巨大优势在于 Set 查找操作(has函数)需要恒定的时间,例如比 nevace 的答案更快。


小智 9

这对我来说很有效,并且在从对象数组中删除时也很有效:

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));
Run Code Online (Sandbox Code Playgroud)

可能有一种更短更有效的方式来写这个,但这确实有效。


Art*_*nov 9

我发现这是最优雅的解决方案:

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

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

console.log(newArray)
Run Code Online (Sandbox Code Playgroud)

输出:

[2, 4]
Run Code Online (Sandbox Code Playgroud)

甚至更短:

const newArray = oldArray.filter(v => !removeItems.includes(v))
Run Code Online (Sandbox Code Playgroud)


ris*_*p89 7

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

MDN参考在这里


Wat*_*uck 6

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

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


sim*_*ack 5

感觉有必要发布带有O(n)时间的答案:)。拼接解决方案的问题在于,由于数组的底层实现实际上是一个数组,因此每次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)
Run Code Online (Sandbox Code Playgroud)

这会从中间开始删除元素,因此每次删除都会迫使js引擎复制n/2元素,我们(n/2)^2总共进行了二次复制操作。

拼接解决方案(假设is已经按照降序排序以消除开销)如下:

for(var i=0; i<is.length; i++)
  xs.splice(is[i], 1)
Run Code Online (Sandbox Code Playgroud)

但是,通过从头开始重建数组,使用蒙版查看是否复制元素(排序会将其推送到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
Run Code Online (Sandbox Code Playgroud)

我在jsperf.com上运行了它,即使n=100是拼接方法也慢了90%。对于更大的n差异将更大。


Kas*_*ner 5

使用 ES5 的简单解决方案。这似乎更适合当今的大多数应用程序,因为许多应用程序不再希望依赖 jQuery 等。

当要移除的索引按升序排序时:

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

removeValFromIndex.reverse().forEach(function(index) {
  valuesArr.splice(index, 1);
});
Run Code Online (Sandbox Code Playgroud)

当要删除的索引未排序时:

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);
});
Run Code Online (Sandbox Code Playgroud)


小智 5

快速 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))
Run Code Online (Sandbox Code Playgroud)