0

I'm trying to create a function that duplicates every 5 found in the provided array by using Array.prototype.forEach() and Array.prototype.splice():

function duplicateFives(array) {
  function multiplyFives (element, index) {
    if (element === 5) {
      array.splice(index, 0, 5);
      index++;
    }
  }
  
  array.forEach(multiplyFives);

  return array;
}

However, it seems modifying the second parameter of the .forEach method doesn't skip iterations (elements). Is this correct, or am I making a different mistake?

Mdn does not seem to confirm nor specify any functionality related to the index parameter.

MD3ad
  • 13
  • 4
  • Yes, it's correct. `index` is a local variable to the callback function, and modifying it doesn't change the outer (native) loop. – Teemu Jul 21 '22 at 16:30
  • 1
    So are you really just trying to chunk your array in groups of 5? – imvain2 Jul 21 '22 at 16:30
  • https://stackoverflow.com/questions/21811630/splicing-a-javascript-array-from-within-the-callback-passed-to-foreach – James Jul 21 '22 at 16:38
  • please add some data and wanted result. – Nina Scholz Jul 21 '22 at 16:39
  • Splitting an array into chunks https://stackoverflow.com/questions/8495687/split-array-into-chunks – imvain2 Jul 21 '22 at 16:46
  • To further clarify my question/issue: Rather than splitting my array I am trying to find elements that are equal to 5 and then add another 5 to the same array, basically duplicating the amount of fives in place. To avoid duplicating duplicates I wanted to know if modifying the index of the forEach method would allow me to skip over the duplicates created. As @Teemu pointed out to me, index is a local variable bound to the callback function and can therefor not change the outer (forEach) loop. – MD3ad Jul 23 '22 at 13:35

4 Answers4

0

If you want to split an array in chunks of n elements, Array.reduce may be a better idea.

const arr = [1,8,4,5,7,8,5,9,12,5,98,97,32,];
let chunks = arr.reduce( (a, v, i) => 
    i && i%5 === 0
     ? [...a, arr.slice(i-5, i)] : a, []);
// remaining elements
const remain = arr.slice(chunks.flat().length);

if (remain.length) {
  chunks = chunks.concat([remain]);
}

console.log(`${JSON.stringify(chunks)}`);
KooiInc
  • 119,216
  • 31
  • 141
  • 177
0

The index is limited to the scope of the multiplyFives() function and won't modify the index of the array.forEach() loop.

With your code, when a new element is spliced onto the array at the next index, the array.forEach() loop will see that element in the next iteration and continue splicing the same element for the remaining length of the array.

A boolean duplicate flag is required to allow duplicating adjacent 5 values and to ignore values that were already duplicated.

Here's the correct JavaScript code with comments explaining each modified line.

const array = [1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]
console.log('Array without duplicated 5 values')
console.log(array)

function duplicateFives(array) {
    // Set a boolean flag to determine if a duplicate 5 should be made
    let duplicate = true

    function multiplyFives (element, index) {
        if (element === 5) {
            if (duplicate === true) {
                // Add a duplicate 5 to the array if the current element isn't from a previous duplication
                array.splice(index, 0, 5)
                // Prevent the duplicated 5 from duplicating itself in the next iteration
                duplicate = false
            } else {
                // Allow duplication for the next element with a value of 5 in the array
                duplicate = true
            }
        }
    }

    array.forEach(multiplyFives)
    return array
}

duplicateFives(array)
console.log('Array with duplicated 5 values')
console.log(array)
0

You can not modify an array while iterating it with a forEach loop, which only provides local variables, like current element and index. Those are just local variables, modifying them does not affect the loop inside forEach.

What you should do is find indexes to be modified, and modify the array itself.

something like:

function duplicateFives(array) {
    array.map((cur,index)=>cur === 5 ? index : undefined) // find indexes of 5's
        .filter(item=>item !== undefined) // filter undefined's
        .forEach((item,index) => array.splice(item + index, 0, 5)); // modify array for those items. 
               // Adding new items to array changes indexes, take that into account.
    return array;
}

console.log(duplicateFives([1, 2, 3, 4, 5, 6, 7, 5, 8, 9, 10]));
Alper Batıoğlu
  • 313
  • 1
  • 2
  • 9
0

Array.forEach() works a bit different. As per the doc, It says that function is executed for each of the elements in the array, in ascending order.

You can simply achieve this by using for loop along with the continue statement which helps in terminates the execution of the statements in the current iteration of the current loop, and continues execution of the loop with the next iteration.

Live Demo :

const arr = [1,2,5,3,4,5,6,7,8,5];

function duplicateFives(array) {
  for (let i = 0; i < array.length; i++) {
    if (array[i] === 5) {
      array.splice(i, 0, 5);
      i++;
      continue;
    }
  }
  
  return array;
}

console.log(duplicateFives(arr))
Debug Diva
  • 26,058
  • 13
  • 70
  • 123