2013-07-25 112 views
3

我有两个数组,available_itemsrequested_items。我想从中删除requested_items中缺少的元素。使用forEach并没有给出预期的结果,因为即使删除一个元素并且下一个元素具有旧索引,内部索引也会增加。for each删除一个元素时跳过一个元素

这是一个测试案例(也this jsbin):

var available_items = [2, 5, 9, 36, 48, 23]; 
var requested_items = [5, 12, 49, 30, 90, 17]; 
requested_items.forEach(function(v, i, a) { 
    if(available_items.indexOf(v) == -1) { 
    console.log("will remove " + i + ' ' + v); 
    a.splice(i, 1); 
    } else console.log("will keep " + i + ' ' + v); 
}); 
console.log('Resulting request array is ' + requested_items.toString()); 

结果是:

"will keep 0 5" 
"will remove 1 12" 
"will remove 2 30" 
"will remove 3 17" 
"Resulting request array is 5,49,90" 

这将重复数万次,因此,使用库(例如,下划线),是我想避免的,如果它们对性能产生不利影响的话。

所以,我的问题是,什么是最便宜的方法来纠正?

+0

为什么不使用'for(var i in blah)'?如果我记得,这保证了在循环之前存在的每个元素至少被访问一次。 – Dave

+1

做一个循环开始在结束和反向工作。 – RobH

+0

那么结果数组应该是什么? – elclanrs

回答

8

使用for循环并向后计数,所以您没有索引问题。

for(var i = requested_items.length - 1; i > 0; i--) { 
    // your logic 
} 

“感觉” 哈克但它的伎俩。

+0

非常好!谢谢。 –

+0

即使使用大型数组,仍然比'filter'更快:http://jsperf.com/reducing-array-with-filter-vs-loop(至少在chrome中) –

2

该规范:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

在foreach功能开始执行前的范围被确定 - 所以你在呼唤i = [0 .. 5] ...元素a[1], a[2], .. a[5]

这些值本身是在访问索引时确定的。所以如果你删除a[1],那么跳到a[2],你就跳过了一个值! (在你的例子中,a[1]会增加49个。)

规范的最后一个重要部分:被删除的索引没有被访问,所以它是一个无声的警告。在一个真实的C++数组中,你会看到一个等价的:'index 4 is out of range! index 5 is out of range!'

有趣的是,如果我是你,我可能会避免在循环中修改这个数组作为原则问题。在其他编程语言中,forEach循环并行执行,并且索引的顺序是而不是 set ..石头修改包含结构导致未定义的行为。从规范中可以看出,这里有一种...呃,你不应该那样做,但是如果你这样做会发生什么......

我的解决方案是创建第三个阵列,并用它来代替:

var found_items = []; 
requested_items.forEach(function(v, i, a) { 
    if(available_items.indexOf(v) !== -1) { 
    found_items.push(v); 
    } 
}); 

一个令人难以置信的哈​​克的方式,让您选择的风格将是使用while()循环每删除一个元素时留在相同的索引。

requested_items.forEach(function(v, i, a) { 
    if(available_items.indexOf(v) == -1) { 
    console.log("will remove " + i + ' ' + v); 
    a.splice(i, 1); 

    while(available_items.indexOf(a[i]) === -1) { 
     console.log("will also remove " + i + ' ' + a[i]); 
     a.splice(i, 1); 
    } 

    } else console.log("will keep " + i + ' ' + v); 
}); 

呃,那很丑。

+0

+1有趣的引擎信息和替代方法。 –