-2

I wrote a function that shuffles the elements of an array.

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;
}

For some reason, the function only returns half of the array elements. If an array of 7 elements is passed to it, it returns 4 elements. Similarly, if an array with 8 elements is returned.

Where did I go wrong?

2 Answers2

1

Just store the length of the array in a variable and use it in a for-loop header instead of arr.length. And that var oldarr = arr line does nothing in your code.

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));

Note that this is just a quick fix to your problem, not the recommended solution.

And to answer you question - why when you have array of 4 items, the array with only 2 items will be returned - let's look at the execution of that loop where you are decreasing the length of the array in each iteration.

iteration;   i;   arr.length;   i < arr.length
   1         0        4             true
   2         1        3             true
   3         2        2             false
Matus Dubrava
  • 13,637
  • 2
  • 38
  • 54
1

There are many Q&A on StackOverflow which provide a correct and efficient algorithm. In your code, the loop variable increments up to arr.length, but in each iteration you diminish that length with splice, so in total, i will only run to about half of the original length, and by consequence your function returns an array of about half the input size.

Quick fix: instead of the for loop, use a while loop:

while (arr.length) {

Optional: in order to leave the input array in tact, replace the following useless assignment:

var oldarr = arr;

...with a copy statement:

arr = arr.slice();
trincot
  • 317,000
  • 35
  • 244
  • 286