Changing an array in place using splice()

  • A+
Category:Languages

I'm trying to write a function that, given an array and n, returns the array with elements repeating no more than n times. I cannot change the order of the array.

Below is the code I have so far. What is perplexing me is that it works for most elements in a given array, but not for some others. I'm trying to find a rhyme or reason for the elements for which the code does not work.

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);

Currently returns this...

[7, 26, 21, 41, 43, 2, 26, 24, 10, 10, 10, 24, 35, 35, 43, 41, 7, 21,  41, 2, 43, 28] 

But I should get this...

[7, 26, 21, 41, 43, 2, 26, 24, 10, 10, 24, 35, 35, 43, 41, 7, 21, 2,  28] 

Any insight into where I'm going wrong would be sincerely appreciated.


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))

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: