20

The code below works for a normal array but not with an array with object does anybody knows how to do this?

const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

function shuffle(array) {
  for (let i = array.length - 1; i > 0; i--) {
    let j = Math.floor(Math.random() * (i + 1));
    let temp = array[i];
    array[i] = array[j];
    array[j] = temp;
  }
  return array;
}

const result = shuffle(array);

console.log(JSON.stringify(result));

5
  • 1
    can you elaborate more what kind of structure of array. Commented Mar 29, 2018 at 11:51
  • 5
    Possible duplicate of How to randomize (shuffle) a JavaScript array? Commented Mar 29, 2018 at 11:52
  • What do you mean by "array with object" ? Commented Mar 29, 2018 at 11:54
  • 3
    This code is agnostic to the content of the array. Replace all numbers to objects - { id: 1 }, { id: 2 }, etc... and you can see it. Commented Mar 29, 2018 at 11:54
  • In my experience, this works except for this one case: an associative array where every element is an array of objects. If I pass one of those array elements (which is itself an array) to this function, then the array is not shuffled. However, if you modify the code to make a copy of the array and then shuffle that and return it, that will work. You must use a legitimate array copy method like: newArray = [...array], in other words, newArray = array won't work. Commented Nov 25, 2019 at 17:13

4 Answers 4

59

Try sorting like this snippet:

console.log( [
    { some: 1 },
    { some: 2 },
    { some: 3 },
    { some: 4 },
    { some: 5 },
    { some: 6 },
    { some: 7 },
  ]
  .sort( () => Math.random() - 0.5) );

In reponse to Martin Omanders comment: here's a shuffle method according to the Fisher-Yates algorithm

const result = document.querySelector("pre");
for (let i=0; i<20; i+=1) {
  result.textContent += 
    JSON.stringify(shuffleFisherYates([0,1,2,3,4,5,6,7,8,9])) + '\n';
}

function shuffleFisherYates(array) {
  let i = array.length;
  while (i--) {
    const ri = Math.floor(Math.random() * i);
    [array[i], array[ri]] = [array[ri], array[i]];
  }
  return array;
}
<pre></pre>

Which may be condensed to a one liner (note: this one liner will not compile in the Google Closure Compiler with level advanced):

const shuffle = array => 
  [...Array(array.length)]
    .map((el, i) => Math.floor(Math.random() * i))
    .reduce( (a, rv, i) => ([a[i], a[rv]] = [a[rv], a[i]]) && a, array);
const result = document.querySelector("pre");
for (let i=0; i<100; i+=1)
  result.textContent +=
   JSON.stringify(shuffle([0,1,2,3,4,5,6,7,8,9])) + '\n';
<pre></pre>

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

2 Comments

Others have pointed out that this solution (while cute and good enough for some uses) isn't very random: stackoverflow.com/a/18650169/455313
The OP is already implementing Fisher-Yates shuffle in his question. So you're saying to do what he's already doing?
3

Here is one more example based on lodash _.shuffle.

const array = [
    { some: 1 },
    { some: 2 },
    { some: 3 },
    { some: 4 },
    { some: 5 },
    { some: 6 },
    { some: 7 },
  ];
console.log(_.shuffle(array));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Comments

0

If you need to shuffle a collection of element nodes (in the DOM), convert it to an array first:

var wrapper = document.getElementById('someid');
var array = Array.prototype.slice.call(wrapper.children);

Shuffling a HTMLCollection object (as returned by children) directly doesn't work even if you can iterate the collection with a for loop. This stumbled me for a while.

Comments

0

I don't have enough reputation points to comment, but @Koolinc's updated function for the Fisher-Yates algorithm has an error in the while loop as it is written. It creates an infinite loop because the while loop never ends. Here is the updated function:

function shuffleFisherYates(array) {
  let i = array.length;
  while (i > 0) {
    const ri = Math.floor(Math.random() * i);
    i--;
    [array[i], array[ri]] = [array[ri], array[i]];
  }
  return array;
}

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.