Перестановка массива возвращает только часть массива

Я написал функцию, которая перемешивает элементы массива.

function shuffle(arr) {
  var newarr = [];
  var oldarr = arr;
  for(var i = 0; i < arr.length; i++) {
    var index = Math.floor(Math.random() * arr.length);
    newarr.push(arr[index]);
    arr.splice(index, 1);
  }
  return newarr;
}

По какой-то причине функция возвращает только половину элементов массива. Если ему передан массив из 7 элементов, он возвращает 4 элемента. Аналогично, если возвращается массив с 8 элементами.

Где я неправ?

2 ответа

Решение

Просто сохраните длину массива в переменной и используйте ее в заголовке цикла for вместо arr.length, И это var oldarr = arr строка ничего не делает в вашем коде.

const arr = [1, 2, 3, 4];

function shuffle(arr) {
  var newarr = [];
  const length = arr.length;

  for (var i = 0; i < length; i++) {
    var index = Math.floor(Math.random() * arr.length);
    newarr.push(arr[index]);
    arr.splice(index, 1);
  }

  return newarr;
}

console.log(shuffle(arr));

Обратите внимание, что это просто быстрое решение вашей проблемы, а не рекомендуемое решение.

И чтобы ответить на ваш вопрос - почему, когда у вас есть массив из 4 элементов, будет возвращен массив только с 2 элементами - давайте посмотрим на выполнение этого цикла, когда вы уменьшаете длину массива в каждой итерации.

iteration;   i;   arr.length;   i < arr.length
   1         0        4             true
   2         1        3             true
   3         2        2             false

В Stackru есть много вопросов и ответов, которые обеспечивают правильный и эффективный алгоритм. В вашем коде переменная цикла увеличивается до arr.length, но в каждой итерации вы уменьшаете length с splice итого, i будет работать только примерно до половины исходной длины, и, как следствие, ваша функция возвращает массив, равный примерно половине входного размера.

Быстрое исправление: вместо for цикл, используйте while цикл:

while (arr.length) {

Необязательно: чтобы оставить входной массив в такте, замените следующее бесполезное назначение:

var oldarr = arr;

... с копией заявления:

arr = arr.slice();
Другие вопросы по тегам