0

i know this is an annoying question, but can someone explain me why splice method is executing in a weird way. Please explain me why the expected output is different from the actual result.


let numbers = [15, 12, 15, 3, 5, 4, 6];

// Get the indexes of the numbers greater than 5
let indexes = numbers.reduce((arr, current, index) => {
  if (current > 5) {
    arr.push(index);
  }

  return arr;
}, []);

// Loop through the indexes while removing the indexes from the numbers array
indexes.forEach((element) => {
  numbers.splice(element, 1);
});

// expected result: numbers = [ 3 , 5, 4 ];
// actual result: numbers = [ 12, 3, 4, 6 ]

3
  • Splice changes the array it is used on. When you remove an array item at a specific index, say... between two other numbers, any other index references are then made invalid, since they will refer to different numbers. Commented Jan 28, 2021 at 7:58
  • So your first number is 15; 15 is at index 0. You remove 15, and then 12 becomes index 0, and so on and so forth. Commented Jan 28, 2021 at 7:59
  • numbers.filter(item => item < 6) Commented Jan 28, 2021 at 8:07

3 Answers 3

3

.splice() changes the array it is used on. You might have already known this, but if you debug your code using a console.log, you'll see what's happening; in short, your first number > 5 is 15. 15 is at index 0, so you remove index 0. However, as splice changes the array it is used on, 12 becomes index 0, and then the second 15 index 1, and so on and so forth. So for example, your code has the following indexes: 0, 1, 2, 6.

  • The first time you remove index 0: [12, 15, 3, 5, 4, 6]
  • Then you remove index 1: [12, 3, 5, 4, 6]
  • Then you remove index 2: [12, 3, 4, 6]
  • Then you remove index 6, which doesn't exist: [12, 3, 4, 6]

The better way of accomplishing that goal is with .filter(). Filter creates a new array of all items that pass the test given in the callback, so:

numbers = numbers.filter((num) => num < 6);

That's the arrow function expression shorthand to return only numbers less than 6.

Sign up to request clarification or add additional context in comments.

Comments

1

splice actually removes the item in place. It does not create any copy of array. In your case after reduce operation, indexes would be

 [0, 1, 2, 6]

and then while iterating and splicing, in first iteration array with position 0 is removed so array becomes

numbers = [12, 15, 3, 5, 4, 6];

and its length is also reduced. On next iteration of forEach array element with index position 1 is removed which is 15 in our case. So after second iteration array becomes

    numbers = [12, 3, 5, 4, 6];

Similarly in next subsequent iteration you will have result like

[12, 3, 4, 6]

Comments

0

As someone has mentioned the problem is with applying changes over an array that is mutated in every iteration.

I assume the example is for learning purposes as it would have been easier to write it like:


let numbers = [15, 12, 15, 3, 5, 4, 6]
numbers.filter(elem => elem <= 5) 

In any case, and following the demonstration code, it would be good to stress the dangerous of mutations that is prone to spooky effects. I have rewritten the code in a more functional style:

let numbers = [15, 12, 15, 3, 5, 4, 6];

// Get the indexes of the numbers greater than 5
let indexes = numbers.reduce((arr, current, index) => {
  if (current > 5) {
    return arr.concat(index);
  }

  return arr;
}, []);

// Instead of removing we create a new array filtering out the elements we dont want
let filteredNumbers = numbers.filter((_,index) => indexes.indexOf(index) === -1)

console.log(filteredNumbers)

// expected result: numbers = [ 3 , 5, 4 ];
// actual result: numbers = [ 3, 5, 4 ]

1 Comment

@Danik_Help can you mark the right answer so other people can learn from your question?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.