Странная ошибка в методе соединения Javascript - PullRequest
6 голосов
/ 30 июня 2019

У меня есть массив, который содержит «нули», и я хочу переместить все «Нули» до последних индексов массива.

Ожидаемый результат:

[1,2,3,0,0,0,0]

Но вместо этого я получаю:

[1,2,0,3,0,0,0]

let a = [0, 1, 2, 0, 0, 3, 0];
let count = 0;
let len = a.length;

for (i = 0; i < len; i++) {
  if (a[i] == 0) {
    count = count + 1;
    a.splice(i, 1);
  }
}

for (j = 0; j < count; j++) {
  a.push(0);
}

console.log(a);

Ответы [ 7 ]

9 голосов
/ 30 июня 2019

При удалении элемента из массива все элементы смещаются вниз на единицу. Когда вы продвигаете свой индекс (i ++), вы пропускаете сдвинутый вниз элемент в массиве, который оказывается последовательным нулем в массиве.

Решение: выполните следующий цикл в обратном направлении, и он заработает.

4 голосов
/ 30 июня 2019

Поскольку сращивание изменяет длину массива, вы можете выполнить итерацию от конца массива и соединить найденное значение непосредственно с последним индексом.

При таком подходе вам потребуется только один цикл.

var a = [0, 1, 2, 0, 0, 3, 0],
    i = a.length;

while (i--) {
    if (a[i] === 0) {
        a.splice(a.length, 0, ...a.splice(i, 1));
    }
}

console.log(a);

Более короткий подход без сращивания - и начинается с нуля.

var a = [0, 1, 2, 0, 0, 3, 0],
    i, j = 0;

for (i = 0; i < a.length; i++) {
    if (a[i] !== 0) {
        [a[j], a[i]] = [a[i], a[j]]; // swap
        j++;
    }        
}

console.log(a);
1 голос
/ 30 июня 2019

В цикле for при сращивании массива массив и его длина изменяются.

для этого вы должны исправить i в цикле for путем вычитания 1

  i++;

и зафиксируйте длину, вычтя 1 или заново определите длину

let a = [0, 1, 2, 0, 0, 3, 0];
let count = 0;
let len = a.length;

for (i = 0; i < len; i++) {
  if (a[i] == 0) {
    count = count + 1;
    a.splice(i, 1);
    len = a.length;
    i--;
  }
}

for (j = 0; j < count; j++) {
  a.push(0);
}

console.log(a);
1 голос
/ 30 июня 2019

Вы можете сделать это намного проще с Array.prototype.sort():

const array = [0, 1, 2, 0, 0, 3, 0];
const sortedArray = array.sort((a, b) => {
  if (a === 0) {
    return 1;
  }
  if (b === 0) {
    return -1;
  }
  return a - b;
});

console.log(sortedArray);
0 голосов
/ 30 июня 2019

Вместо сращивания массива снова и снова, здесь используется другой подход:

let a = [0, 1, 2, 0, 0, 3, 0];
// create some more (random) data
for (let i = a.length; i < 30; ++i)
  a[i] = Math.floor(Math.random() * Math.random() * 10);
console.log(""+a);

let i = 0, j = 0, len = a.length;
// move non-0 values to the front
while (i < len) {
  if (a[i] !== 0) {
    a[j++] = a[i];
  }
  ++i;
}
// fill the end of the list with 0
while (j < len) a[j++] = 0;

console.log(""+a);
0 голосов
/ 30 июня 2019

Обратите внимание, что каждый вызов splice обычно имеет O (n) сложность . Есть много способов достичь желаемого результата на порядок более эффективно за одну итерацию O (n). Вот один из них:

let a = [0, 1, 2, 0, 0, 3, 0]

for (let i=0, j=0; j<a.length; j++)
  if (a[j] && i != j)
    [a[i++], a[j]] = [a[j], 0]

console.log(a)
0 голосов
/ 30 июня 2019

Вы можете добавлять i--; и len--; каждый раз, когда используете соединение:

let a = [0, 1, 2, 0, 0, 3, 0];
let count = 0;
let len = a.length;

for (i = 0; i < len; i++) {
  if (a[i] == 0) {
    count = count + 1;
    a.splice(i, 1);
    i--; len--;
  }
}

for (j = 0; j < count; j++) {
  a.push(0);
}

console.log(a);

Это потому, что когда вы соединяете 1 элемент, ключи массива смещаются вниз на один, поэтому ключ следующего элемента, который вы хотите проверить, совпадает с ключом, который вы только что удалили. Значение len также корректируется с помощью len--;, потому что мы только что удалили элемент.

Хотя этот ответ является правильным способом сделать это с использованием вашего первоначального плана, это своего рода исправление. Ваша проблема заключалась в том, что вы зацикливаетесь на массиве, и этот массив теряет элементы во время цикла, и, как правило, правильный подход в этих ситуациях заключается в зацикливании в обратном направлении. Таким образом, элементы, которые рискуют изменить свой ключ во время цикла, являются элементами, которые мы уже проверили.

...