Как правильно переместить элемент массива в конец?

Нужно все элементы массива со значением 0 переместить в конец массива.

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

Именно в приведенном примере все работает хорошо, а вот когда есть 2 или больше нуля подряд, то возникает проблема.

moveZeros(["a",0,"b","c","d",1,1,3,1,9,0,0,9,0,0,0,0,0,0,0]) // returns["a", "b", "c", "d", 1, 1, 3, 1, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0]  

Вот мой код:

function moveZeros (arr) {
  arr.forEach(function(item, index) {
    if (item === 0) {
      arr.push(item);
      arr.splice(index, 1);
    }
  });
  return arr;
}

Если я правильно понял, то причиной такого поведения является смещение в счетчике, но я не знаю как решить эту проблему. Для удобства мой код на CodePen


Ответы (4 шт):

Автор решения: Yugofx
const arr = [false,1,0,1,2,0,1,3,"a"];
function moveZeros(arr) {
    let upperBound = arr.length;
    for (let i = 0; i < upperBound; i++) {
        if (arr[i] === 0) {
            arr.push(0);
            arr.splice(i, 1);
            upperBound--;
            i--;
        }
    }
    return arr;
}
console.log(arr);

Если наткнулись на ноль, то просто искусственно приостанавливаем итератор на том же индексе (i--) и продолжаем исследование с него же.

upperBound нужен только для того, чтобы не катать массив до конца, ведь в конце мы копим нули. Получится в итоге один полный проход по массиву.

→ Ссылка
Автор решения: Данил Черкашин

может просто посчитать кол-во нулей в вашем массиве пусть это будет число n, удалить из исходного массива все нули, и просто присоединить в конец исходного массива массив нулей длиной равной n

var sample_arr = ["a",0,"b","c","d",1,1,3,1,9,0,0,9,0,0,0,0,0,0,0];

let move_zeros = function(arr) {
    var zeros = [];

    for (let i=0; i < sample_arr.length; i++) {
        if (sample_arr[i] == 0) {
            zeros.push(0)
            arr.splice(i, 1)
        }
    }

    arr.concat(zeros)

    return arr
}

console.log(move_zeros(sample_arr))
→ Ссылка
Автор решения: Alexander Lonberg

let arr = ["a", 0, "b", "c", "d", 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0]

function moveZeros(arr) {
  // Исключаем последние 0 для оптимизации - не вызывает лишний раз push() и splice()
  let i = arr.length
  while (i && (arr[--i] === 0));
  // Идем в обратном направлении, чтоб не следить за текущими индексами
  for (; i >= 0; --i) {
    if (arr[i] === 0) {
      arr.push(arr.splice(i, 1)[0])
    }
  }
  return arr
}

console.log(moveZeros(arr))

→ Ссылка
Автор решения: Yaant

function moveZeros(arr) {
  let filtered = arr.filter(el => el !== 0);
  return filtered.concat(Array(arr.length - filtered.length).fill(0));
}

console.log(moveZeros([false, 1, 0, 1, 2, 0, 1, 3, "a"])+'');
console.log(moveZeros(["a",0,"b","c","d",1,1,3,1,9,0,0,9,0,0,0,0,0,0,0])+''); 

→ Ссылка