1

I am trying to solve a problem that takes an array and moves all of the zeros to the end, preserving the order of the other elements.

This isn't iterating through the entire array, any ideas on what I'm doing wrong would be greatly appreciated.

let moveZeros = function (arr) {
  let newArr = [];
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === 0) {
      newArr.push(arr[i]);
      arr.splice(i, 1);
    }
  }
  return arr.concat(newArr);
};

moveZeros([9, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0]);

// expexted to return [9,9,1,2,1,1,3,1,9,9,0,0,0,0,0,0,0,0,0,0]
// currently returns  [9,9,1,2,1,1,3,1,9,0,9,0,0,0,0,0,0,0,0,0]

// Strangely... sending a smaller array to the function seems to work.

//moveZeros([false,1,0,1,2,0,1,3,"a"])
// correctly returns[false,1,1,2,1,3,"a",0,0]

4
  • you know arr.splice removes elements from the array, right? so, the i++ in the for loop probably makes yo skip an element Commented Jul 23, 2021 at 12:16
  • try arr.splice(i--, 1); - the reason a "shorter" input seems to work is that your "shorter" input never has 2 zeros in a row Commented Jul 23, 2021 at 12:18
  • Great example of why changing the length of an array while you're looping through it is probably not the best idea. Commented Jul 23, 2021 at 12:27
  • Try to find a failing example and start debugging. Commented Jul 23, 2021 at 12:27

2 Answers 2

2

The problem isn't related to the length, it occurs when you have more than one consecutive 0. For example [0,0,9,0,0,9] will come out [0,9,0,9,0,0].

In the first iteration of the loop (i=0), you remove the first 0 from the array, leaving you with [0,9,0,0,9]. On the second iteration (i=1), it's now looking at the second element in the array, which is 9. The first 0 is skipped. This will happen later in the array too as the loop progresses.

In general it can be problematic to modify an array as you loop through it. There are a number of ways you could perform a sort like this. But to keep it close to your original you could do this:

let moveZeros = function(arr) {
    let arrA = [];
    let arrB = [];
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === 0) {
            arrB.push(arr[i]);
        } else {
            arrA.push(arr[i]);
        }
    }
    return arrA.concat(arrB);
};

Now the function keeps the original array intact as it goes through it. Non-0 items are pushed to arrA, and 0s are pushed to arrB, and then those two are concatenated.

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

1 Comment

Thank you for the description Josh that's really good to know I will bear that in mind for the future. Nicely done, solved so quickly!
0

You could keep the array and move all not zero values to the start and fill the rest with zeroes.

let moveZeros = function(array) {
        let i = 0,
            j = 0;

        while (i < array.length) {
            if (array[i] !== 0) array[j++] = array[i];
            i++;
        }

        while (j < array.length) array[j++] = 0;

        return array;
    };

console.log(...moveZeros([9, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0]));
console.log(...moveZeros([false, 1, 0, 1, 2, 0, 1, 3, "a"]));

Comments

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.