我有一个对象数组。我试图找到重复的对象,然后删除该对象的两个实例。
现在我正在使用这个方法:
function checkForDups(data){
for(var i = 0; i < data.length; i++){
for(var j = i+1; j < data.length; j++){
if(data[j].number === data[i].number){
data.splice(j,1);
data.splice(i,1);
}
}
}
return data;
}
我认为问题是它只检查索引大于当前位置的重复项。这意味着在数组中"后面"的对象不会被检查是否重复。目前,我通过这个函数运行数组几次以获得所需的结果。然而,这显然是极其低效的。我怎样才能更有效地达到我想要的结果?
我认为问题是它只检查索引大于当前位置的重复项。这意味着在数组中"后面"的对象不会被检查是否重复。
不,这是一个简单的优化,通过相等关系的对称性使之成为可能。通过提前搜索并删除你面前的所有重复项,任何当前项都不能是前一个项的重复项,否则它就已经被消除了。
然而,有一些事情你没有注意到:
- 当从数组中拼接(删除)一个项目时,所有后续的项目都会被移动,数组的长度也会改变。要真正检查数组中的所有项目,您需要在删除时减少(或:不增加)计数器变量,以便访问现在与被删除的项目在同一位置的新项目(您刚刚删除的地点需要重新访问)。
- 您可能希望在找到重复项后将内循环
break
,否则您将比较并删除完全不同的项。 -
你还没有明确的算法应该做什么,当有超过2个相同排序的重复项目在数组中。如果对方的号码是奇数,留下一个?谢谢你的评论。
要删除所有现有的重复项,您需要继续搜索,但一定不要立即删除i
th元素,否则您将没有任何东西可以进一步比较-或者您甚至可能多次删除i
th项(参见#2)。
所以这个修改应该适合:
function removeAllDups(data) {
// leaves only items in the array that appeared a single time
// removes everything whose .number can be found multiple times
for (var i = 0; i < data.length; i++) {
var found = false,
num = data[i].number;
for (var j = i+1; j < data.length; j++) {
if (data[j].number === num) {
found = true;
data.splice(j--, 1);
}
}
if (found) {
data.splice(i--, 1);
}
}
return data;
}
这是另一种实现。这只使用两次遍历数组,并在情况> 2时删除所有重复:http://jsfiddle.net/nrabinowitz/1pdr780j/
function removeDupes(arr, test) {
test = test || function(a, b) { return a === b; };
function find(cache, element) {
return cache.some(test.bind(null, element));
}
var seen = [];
var dupes = [];
var len = arr.length;
var x;
var current;
// First pass - find dupes
for (x = 0; x < len; x++) {
current = arr[x];
if (find(seen, current)) {
dupes.push(current);
} else {
seen.push(current);
}
}
// Second pass: remove dupes. Reverse iteration saves headaches here
for (x = len - 1; x >= 0; x--) {
current = arr[x];
if (find(dupes, current)) {
arr.splice(x, 1);
}
}
}
这是一个更新的版本,它采用一个可选的测试函数来确定是否相等。对于OP的情况,调用将是
removeDupes(arr, function(a, b) {
return a.number == b.number;
});
注意,这假设支持ES5方法- Array#some
, Function#bind
。如果你需要支持旧的浏览器,一个ES5 shim或者Underscore库就可以了。
您可以使用underscore.js
:
function checkForDups(data) {
return (
_.map(
_.filter(
_.pairs(
_.countBy(data)
), function(v) {return v[1] == 1}
), function(v) {return ~~v[0]}
)
)
}
>> console.log(checkForDups([0,1,2,3,0,1,0,4]))
[2, 3, 4]
>> console.log(checkForDups([0,1,2,3,0,1,0,4]))
[2, 3, 4]