Changing an array in place using splice()
The logic of where you places the while loop is wrong, you need to place it outside of the for loop.
function deleteNth(arr, n) {
arr.forEach(function(item, index) {
var count = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === item) {
count++;
}
}
while (count > n) {
var remove = arr.lastIndexOf(item);
arr.splice(remove, 1);
count--;
}
});
return arr;
}
var x = deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35,
35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41,
35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7,
2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10
], 2);
console.log(x);
Why? Because when you are doing your loop and you remove things from it, you shift things back down. So when you have two items side by side and you remove the first the second one shifts down one spot to fill what you just removed. The i
does not change so you do not check the item that just filled the gap.
What would I do? I would just keep track of the items as I get to it and if I have not gone over the max append it.
function cleanUp (arr, max) {
const cnts = {} // keep track of what we find
return arr.reduce((a, i) => { // loop over the array index by index
cnts[i] = (cnts[i] || 0) + 1; // mark that I seen the number
if (cnts[i] <= max) { // check to see if we are under the max
a.push(i) //if we are, add it to an arry
}
return a // return the array for reduce
}, [])
}
console.log(cleanUp([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35,
35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41,
35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7,
2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2))
For a fast mutating version, you could use a single while
loop, a hash table for counting the items and an adjustment of the index if a splice happens.
function deleteNth(array, n) {
var counter = Object.create(null),
i = 0, v;
while (i < array.length) {
v = array[i];
if (!counter[v]) {
counter[v] = 0;
}
if (++counter[v] > n) {
array.splice(i, 1);
continue;
}
i++;
}
return array;
}
console.log(deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
A better way is to use filter and return a new array.
function deleteNth(array, n) {
var counter = Object.create(null);
return array.filter(v => (counter[v] = (counter[v] || 0) + 1) <= n);
}
console.log(deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This code works:
function deleteNth(arr,n){
var rem = new Array(), new_arr = new Array();
arr.forEach(function (item, index) {
if(!rem[item]) rem[item]=0;
if(rem[item]<n){
new_arr.push(item);
rem[item]++;
}
});
return new_arr;
}
console.log(deleteNth([7, 26, 21, 41, 43, 2, 26, 24, 10, 26, 10, 10, 24, 35, 35, 35, 43, 26, 41, 7, 24, 24, 21, 24, 10, 35, 10, 7, 24, 7, 35, 26, 41, 35, 2, 43, 24, 2, 41, 26, 41, 7, 7, 26, 2, 10, 43, 10, 35, 41, 24, 7, 2, 2, 7, 2, 26, 24, 26, 43, 43, 21, 10, 28, 10], 2));