By Click Upvote


2010-03-15 22:37:11 8 Comments

I have an array like this:

var arr1 = ["a", "b", "c", "d"];

How can I randomize / shuffle it?

30 comments

@Hafizur Rahman 2018-04-01 12:15:07

Though there are a number of implementations already advised but I feel we can make it shorter and easier using forEach loop, so we don't need to worry about calculating array length and also we can safely avoid using a temporary variable.

var myArr = ["a", "b", "c", "d"];

myArr.forEach((val, key) => {
  randomIndex = Math.ceil(Math.random()*(key + 1));
  myArr[key] = myArr[randomIndex];
  myArr[randomIndex] = val;
});
// see the values
console.log('Shuffled Array: ', myArr)

@Ben Carp 2017-09-11 18:12:18

Some of the answers could be shortened using ES6 syntax.

ES6 Pure, Iterative

const getShuffledArr = arr => {
    const newArr = arr.slice()
    for (let i = newArr.length - 1; i > 0; i--) {
        const rand = Math.floor(Math.random() * (i + 1));
        [newArr[i], newArr[rand]] = [newArr[rand], newArr[i]];
    }
    return newArr
};

I personally use this function as it is pure, relatively simple, and according to my tests on Google Chrome the most efficient (compared to other pure versions).

Shuffle Array In place

function getShuffledArr (array){
    for (let i = array.length - 1; i > 0; i--) {
        const rand = Math.floor(Math.random() * (i + 1));
        [array[i], array[rand]] = [array[rand], array[i]]
    }
}

Reliability and Performance

As you can see in this page, there have been incorrect solutions offered here in the past. So, with reliability and performance in mind, I wrote the following function to test any pure (no side effects) array randomizing functions. I used it to test all the options presented in this answer.

function testShuffledArrayFun(getShuffledArrayFun){
    const arr = [0,1,2,3,4,5,6,7,8,9]

    let countArr = arr.map(el=>{
        return arr.map(
            el=> 0
        )
    }) //   For each possible position in the shuffledArr and for 
       //   each possible value, we'll create a counter. 
    const t0 = performance.now()
    const n = 1000000
    for (let i=0 ; i<n ; i++){
        //   We'll call getShuffledArrayFun n times. 
        //   And for each iteration, we'll increment the counter. 
        const shuffledArr = getShuffledArrayFun(arr)
        shuffledArr.forEach(
            (value,key)=>{countArr[key][value]++}
        )
    }
    const t1 = performance.now()
    console.log(`Count Values in position`)
    console.table(countArr)

    const frequencyArr = countArr.map( positionArr => (
        positionArr.map(  
            count => count/n
        )
    )) 

    console.log("Frequency of value in position")
    console.table(frequencyArr)
    console.log(`total time: ${t1-t0}`)
}

Typescript - type for a pure array randomizing function

You can use either of the following.

type GetShuffledArr= <T>(arr:Array<T>) => Array<T> 
interface IGetShuffledArr{
    <T>(arr:Array<T>): Array<T>
}

Other Options

ES6 Pure, Recursive

const getShuffledArr = arr => {
    if (arr.length === 1) {return arr};
    const rand = Math.floor(Math.random() * arr.length);
    return [arr[rand], ...getShuffledArr(arr.filter((_, i) => i != rand))];
};

This version is less efficient than the iterative pure version.

ES6 Pure using array.map

function getShuffledArr (arr){
    return [...arr].map( (_, i, arrCopy) => {
        var rand = i + ( Math.floor( Math.random() * (arrCopy.length - i) ) );
        [arrCopy[rand], arrCopy[i]] = [arrCopy[i], arrCopy[rand]]
        return arrCopy[i]
    })
}

This version is slightly less efficient than the iterative pure version.

ES6 Pure using array.reduce

function getShuffledArr (arr){
    return arr.reduce( 
        (newArr, _, i) => {
            var rand = i + ( Math.floor( Math.random() * (newArr.length - i) ) );
            [newArr[rand], newArr[i]] = [newArr[i], newArr[rand]]
            return newArr
        }, [...arr]
    )
}

This version is slightly less efficient than the iterative pure version.

@sheriffderek 2017-09-11 19:00:09

So, where is the ES6(ES2015) ? [array[i], array[rand]]=[array[rand], array[i]] ? Maybe you can outline how that works. Why do you choose to iterate downwards?

@Ben Carp 2017-09-12 02:47:33

@sheriffderek Yes, the ES6 feature I'm using is the assignment of two vars at once, which allows us to swap two vars in one line of code.

@Ben Carp 2017-09-15 01:00:10

Credit to @sheriffderek who suggested the ascending Algorithm. The ascending algorithm could be proved in induction.

@iPhoney 2018-12-21 06:45:59

For those of us who are not very gifted but have access to the wonders of lodash, there is such a thing as lodash.shuffle.

@Laurens Holst 2012-09-28 20:20:11

Here is a JavaScript implementation of the Durstenfeld shuffle, a computer-optimized version of Fisher-Yates:

/**
 * Randomize array element order in-place.
 * Using Durstenfeld shuffle algorithm.
 */
function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

The Fisher-Yates algorithm works by picking one random element for each original array element, and then excluding it from the next draw. Just like randomly picking from a deck of cards.

This exclusion is done in a clever way (invented by Durstenfeld for use by computers) by swapping the picked element with the current element, and then picking the next random element from the remainder. For optimal efficiency, the loop runs backwards so that the random pick is simplified (it can always start at 0), and it skips the last element because there are no other choices anymore.

The running time of this algorithm is O(n). Note that the shuffle is done in-place. So if you do not want to modify the original array, make a copy of it first with .slice(0).

Updating to ES6 / ECMAScript 2015

The new ES6 allows us to assign two variables at once. This is especially handy when we want to swap the values of two variables, as we can do it in one line of code. Here is a shorter form of the same function, using this feature.

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

@Laurens Holst 2012-09-28 20:47:51

p.s. The same algorithm as ChristopheD’s answer, but with explanation and cleaner implementation.

@Pacerier 2014-10-31 12:32:11

People are attributing the wrong person for the algorithm. It's not Fisher-Yates shuffle but Durstenfeld shuffle. The true original Fisher-Yates algorithm is runs in n^2 time, not n time

@Hengameh 2015-09-22 00:31:49

Could you please tell me which one you think is better for shuffling? (Link: ideone.com/pfRanN). As i tested, there is no difference between them.

@Joel Trauger 2016-08-09 13:31:21

It is not required to return array since JavaScript passes arrays by reference when used as function arguments. I assume this is to save on stack space, but it's an interesting little feature. Performing the shuffle on the array will shuffle the original array.

@Marjan Venema 2016-12-18 20:17:49

The implementation in this answer favors the lower end of the array. Found out the hard way. Math.random() should not be multiplied with the loop counter + 1, but with array.lengt()`. See Generating random whole numbers in JavaScript in a specific range? for a very comprehensive explanation.

@smarx 2017-03-11 01:44:06

@MarjanVenema Not sure if you're still watching this space, but this answer is correct, and the change you're suggesting actually introduces bias. See blog.codinghorror.com/the-danger-of-naivete for a nice writeup of this mistake.

@Marjan Venema 2017-03-11 14:54:08

Not very active anymore but I do keep track of notifications, @smarx. Thanks for that. Interesting read. What I don't understand is why I saw a definite bias towards the lower end using the code above? See softwareonastring.com/1135/perils-of-copy-paste-programming After using the solution from the answer I linked in my comment, distribution seemed much more even.

@smarx 2017-03-11 17:39:35

@MarjanVenema I have no explanation for that. Perhaps there was some other bug in your code. What was your sample size when you looked at the results? Perhaps the pattern you noticed at first was just dumb luck.

@Marjan Venema 2017-03-12 12:23:11

Code was a straight copy of this post ;) I guess it was indeed just dumb luck, but as the task attached to the outcome was considered a "chore" rather than something nice, complaints ran rampant... You know developers: there must be something wrong with your code.

@roottraveller 2017-07-27 14:18:33

@LaurensHolst why we are running from last index to first index i.e n-1 to 0? Is there any particular advantage that I'm unable to see here ??

@Laurens Holst 2017-07-31 21:39:08

@roottraveller It simplifies the code. If it ran forwards the random range would need to be calculated (len - i), and the resulting random index would need to be offset by the current position (+ i). I allude to this in the description, but maybe this makes it more clear. Try to rewrite it yourself, and see!

@bryc 2017-11-25 09:47:02

for (let i = array.length - 1; i > 0; i--) should be for (let i = array.length - 1; i >= 0; i--). It appears to be missing the first array index.

@Laurens Holst 2017-12-11 19:00:36

@bryc As mentioned in the description, “it skips the last element because there are no other choices anymore.” Math.floor(Math.random() * (0 + 1)) will always return 0, and would thus only swap with itself, so there’s no point in doing the last swap.

@user7776077 2018-03-24 12:46:55

this ES6 script works just perfect, thank you so much!

@Martin Burch 2018-05-08 13:10:11

Does this need a return array; at the end?

@nnyby 2018-12-07 19:41:48

@MartinBurch here's a version that doesn't modify the original array and returns a new one. gist.github.com/nikolas/96586a0b56f53eabfd6fe4ed59fecb98

@abumalick 2017-05-19 13:23:11

A simple modification of CoolAJ86's answer that does not modify the original array:

 /**
 * Returns a new array whose contents are a shuffled copy of the original array.
 * @param {Array} The items to shuffle.
 * https://stackoverflow.com/a/2450976/1673761
 * https://stackoverflow.com/a/44071316/1673761
 */
const shuffle = (array) => {
  let currentIndex = array.length;
  let temporaryValue;
  let randomIndex;
  const newArray = array.slice();
  // While there remains elements to shuffle...
  while (currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;
    // Swap it with the current element.
    temporaryValue = newArray[currentIndex];
    newArray[currentIndex] = newArray[randomIndex];
    newArray[randomIndex] = temporaryValue;
  }
  return newArray;
};

@thomas-peter 2018-10-03 10:45:10

A functional solution using Ramda.

const {map, compose, sortBy, prop} = require('ramda')

const shuffle = compose(
  map(prop('v')),
  sortBy(prop('i')),
  map(v => ({v, i: Math.random()}))
)

shuffle([1,2,3,4,5,6,7])

@Xavier Guihot 2018-08-06 21:35:08

d3.js provides a built-in version of the Fisher–Yates shuffle:

console.log(d3.shuffle(["a", "b", "c", "d"]));
<script src="http://d3js.org/d3.v5.min.js"></script>

d3.shuffle(array[, lo[, hi]]) <>

Randomizes the order of the specified array using the Fisher–Yates shuffle.

@Evgenia Manolova 2018-01-13 23:16:03

a shuffle function that doesn't change the source array

Update: Here I'm suggesting a relatively simple (not from complexity perspective) and short algorithm that will do just fine with small sized arrays, but it's definitely going to cost a lot more than the classic Durstenfeld algorithm when you deal with huge arrays. You can find the Durstenfeld in one of the top replies to this question.

Original answer:

If you don't wish your shuffle function to mutate the source array, you can copy it to a local variable, then do the rest with a simple shuffling logic.

function shuffle(array) {
  var result = [], source = array.concat([]);

  while (source.length) {
    let index = Math.floor(Math.random() * source.length);
    result.push(source[index]);
    source.splice(index, 1);
  }

  return result;
}

Shuffling logic: pick up a random index, then add the corresponding element to the result array and delete it from the source array copy. Repeat this action until the source array gets empty.

And if you really want it short, here's how far I could get:

function shuffle(array) {
  var result = [], source = array.concat([]);

  while (source.length) {
    let index = Math.floor(Math.random() * source.length);
    result.push(source.splice(index, 1)[0]);
  }

  return result;
}

@user9315861 2018-07-09 04:49:23

This is essentially the original Fisher-Yates algorithm, with your splice being a horribly inefficient way to do what they called "striking out". If you don't want to mutate the original array, then just copy it, and then shuffle that copy in place using the much more efficient Durstenfeld variant.

@Evgenia Manolova 2018-07-20 11:10:21

@torazaburo, thank you for your feedback. I've updated my answer, to make it clear that I'm rather offering a nice-looking solution, than a super-scaling one

@superluminary 2017-10-03 13:16:52

You can do it easily with map and sort:

let unshuffled = ['hello', 'a', 't', 'q', 1, 2, 3, {cats: true}]

let shuffled = unshuffled
  .map((a) => ({sort: Math.random(), value: a}))
  .sort((a, b) => a.sort - b.sort)
  .map((a) => a.value)
  1. We put each element in the array in an object, and give it a random sort key
  2. We sort using the random key
  3. We unmap to get the original objects

You can shuffle polymorphic arrays, and the sort is as random as Math.random, which is good enough for most purposes.

Since the elements are sorted against consistent keys that are not regenerated each iteration, and each comparison pulls from the same distribution, any non-randomness in the distribution of Math.random is canceled out.

@Rexford 2017-12-06 08:31:47

This is short and sweet.

@Bergi 2017-12-06 19:42:40

@superluminary Oops, you're right. Notice that this answer already used the same approach.

@superluminary 2017-12-07 11:24:08

@Bergi - Ah yes, you are right, although I think my implementation is slightly prettier.

@Mark Grimes 2018-06-29 10:43:18

Very nice. This is the Schwartzian transform in js.

@user9315861 2018-07-08 07:25:30

But performance is worse than FY.

@superluminary 2018-07-09 12:28:36

@torazaburo - It's not as performant as Fischer Yates, but it's prettier and the code is smaller. Code is always a trade-off. If I had a large array, I would use Knuth. If I had a couple of hundred items, I would do this.

@HynekS 2018-10-26 17:51:10

I like the simplicity of this code, but it is incomparably slower than Fischer-Yates – see this JSPerf test. I would also suggest using Symbol, e.g. [Symbol.sort] to prevent collision with a property name.

@superluminary 2018-11-05 11:45:59

@HynekS - It's not fast code I agree, but it's simple. The difference should only be noticeable on quite large arrays. The objects inherit directly from Object, so there should be no collision with the sort attribute. I don't think Symbols are necessary here?

@HynekS 2018-11-05 12:13:14

@superluminary: You are absolutely right about Symbols, I was thinking about the edge of sorting an array including {sort: 'something'} objects, but I did a test and it works perfectly, no need for Symbols. I believe that if your array is 'short', you can afford the performance cost, but I did a test on arrays of 1000 elements – and the test speaks fot itself, see the link to JSPerf.

@TinhNQ 2018-06-20 06:59:22

You can do it easily with:

// array
var fruits = ["Banana", "Orange", "Apple", "Mango"];
// random
fruits.sort(function(a, b){return 0.5 - Math.random()});
// out
console.log(fruits);

Please reference at JavaScript Sorting Arrays

@user9315861 2018-07-08 07:27:11

This algorithm has long been proven to be defective.

@TinhNQ 2018-07-09 05:14:18

Please prove to me. I based on w3schools

@user9315861 2018-07-09 09:09:39

You could read the thread at css-tricks.com/snippets/javascript/shuffle-array, or at news.ycombinator.com/item?id=2728914. W3schools has always been, and remains, a horrible source of information.

@Alexander Mills 2018-07-13 03:50:13

Yes this is not the right way to do it

@Syed Ayesha Bebe 2018-04-23 13:10:43

By using shuffle-array module you can shuffle your array . Here is a simple code of it .

var shuffle = require('shuffle-array'),
 //collection = [1,2,3,4,5];
collection = ["a","b","c","d","e"];
shuffle(collection);

console.log(collection);

Hope this helps.

@Redu 2017-08-30 18:10:58

Just to have a finger in the pie. Here i present a recursive implementation of Fisher Yates shuffle (i think). It gives uniform randomness.

Note: The ~~ (double tilde operator) is in fact behaves like Math.floor() for positive real numbers. Just a short cut it is.

var shuffle = a => a.length ? a.splice(~~(Math.random()*a.length),1).concat(shuffle(a))
                            : a;

console.log(JSON.stringify(shuffle([0,1,2,3,4,5,6,7,8,9])));

@Kris Selbekk 2017-04-05 15:38:39

A very simple way for small arrays is simply this:

const someArray = [1, 2, 3, 4, 5];

someArray.sort(() => Math.random() - 0.5);

It's probably not very efficient, but for small arrays this works just fine. Here's an example so you can see how random (or not) it is, and whether it fits your usecase or not.

const resultsEl = document.querySelector('#results');
const buttonEl = document.querySelector('#trigger');

const generateArrayAndRandomize = () => {
  const someArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
  someArray.sort(() => Math.random() - 0.5);
  return someArray;
};

const renderResultsToDom = (results, el) => {
  el.innerHTML = results.join(' ');
};

buttonEl.addEventListener('click', () => renderResultsToDom(generateArrayAndRandomize(), resultsEl));
<h1>Randomize!</h1>
<button id="trigger">Generate</button>
<p id="results">0 1 2 3 4 5 6 7 8 9</p>

@Azarus 2017-04-10 20:00:21

Nice one, but does generate a complete random elements every time?

@Kris Selbekk 2017-04-11 11:00:59

Not quite sure if I understood you correctly. This approach will indeed shuffle the array in a random way (albeit pseudo-random) every time you call the sort array - it's not a stable sort, for obvious reasons.

@Kris Selbekk 2017-04-27 12:53:18

I didn't quite understand the down-vote here - care to comment? =)

@Azarus 2017-04-27 15:00:25

Wasn't me, but however i dont understand why its downvoted either.

@AlexC 2017-06-23 10:41:18

For the same reasons as explained at stackoverflow.com/a/18650169/28234 . This is much more likely to leave early elements near the start of the array.

@Daniel Griscom 2017-11-03 18:48:18

This is a great, easy one-liner for when you need to scramble an array, but don't care too much about having the results be academically provably random. Sometimes, that last few inches to perfection take more time than it's worth.

@superluminary 2018-03-14 14:34:07

It would be lovely if this worked, but it doesn't. Because of the way quick-search works, an inconsistent comparator will be likely to leave array elements close to their original position. Your array will not be scrambled.

@Kris Selbekk 2018-03-16 13:09:44

Yet it is scrambled though. Try running [1,2,3,4,5].sort(() => Math.random() * 2 - 1); in the console, it'll scramble the result for every time. This isn't the perfect randomizer, but for simple use-cases it works just fine.

@Daniel Martin 2018-06-22 06:31:48

I don't think the comments here adequately warn how bad this method is if you want an even vaguely fair shuffle. Testing this method on chrome with an array of ten elements, the last element stays the last element HALF the time, and 75% of the time is in the last two. This isn't "academic" - it's really quite bad. OTOH, if you want to subtly make something that seems random but lets you cheat by often knowing characteristics of the supposedly shuffled list, I guess this could be used for that.

@icl7126 2018-03-15 18:14:29

Modern short inline solution using ES6 features:

['a','b','c','d'].map(x => [Math.random(), x]).sort(([a], [b]) => a - b).map(([_, x]) => x);

(for educational purposes)

@HMR 2018-02-09 03:32:20

Funny enough there was no non mutating recursive answer:

var shuffle = arr => {
  const recur = (arr,currentIndex)=>{
    console.log("fuck?",JSON.stringify(arr))
    if(currentIndex===0){
      return arr;
    }
    const randomIndex = Math.floor(Math.random() * currentIndex);
    const swap = arr[currentIndex];
    arr[currentIndex] = arr[randomIndex];
    arr[randomIndex] = swap;
    return recur(
      arr,
      currentIndex - 1
    );
  }
  return recur(arr.map(x=>x),arr.length-1);
};

var arr = [1,2,3,4,5,[6]];
console.log(shuffle(arr));
console.log(arr);

@Bergi 2018-02-09 04:08:54

Maybe there wasn't because it's pretty inefficient? :-P

@HMR 2018-02-09 06:48:13

@Bergi Correct, updated with first answer logic. Still need to copy the array for immutability. Added because this is flagged as the duplicate of a question asking for a function that takes an array and returned a shuffled array without mutating the array. Now the question actually has an answer the OP was looking for.

@Mudlabs 2018-01-30 01:54:01

// Create a places array which holds the index for each item in the
// passed in array.
// 
// Then return a new array by randomly selecting items from the
// passed in array by referencing the places array item. Removing that
// places item each time though.
function shuffle(array) {
    let places = array.map((item, index) => index);
    return array.map((item, index, array) => {
      const random_index = Math.floor(Math.random() * places.length);
      const places_value = places[random_index];
      places.splice(random_index, 1);
      return array[places_value];
    })
}

@Saksham Khurana 2018-01-29 10:06:33

I have written a shuffle function on my own . The difference here is it will never repeat a value (checks in the code for this) :-

function shuffleArray(array) {
 var newArray = [];
 for (var i = 0; i < array.length; i++) {
     newArray.push(-1);
 }

 for (var j = 0; j < array.length; j++) {
    var id = Math.floor((Math.random() * array.length));
    while (newArray[id] !== -1) {
        id = Math.floor((Math.random() * array.length));
    }

    newArray.splice(id, 1, array[j]);
 }
 return newArray; }

@Thomas Baruchel 2017-02-19 15:23:58

From a theoretical point of view, the most elegant way of doing it, in my humble opinion, is to get a single random number between 0 and n!-1 and to compute a one to one mapping from {0, 1, …, n!-1} to all permutations of (0, 1, 2, …, n-1). As long as you can use a (pseudo-)random generator reliable enough for getting such a number without any significant bias, you have enough information in it for achieving what you want without needing several other random numbers.

When computing with IEEE754 double precision floating numbers, you can expect your random generator to provide about 15 decimals. Since you have 15!=1,307,674,368,000 (with 13 digits), you can use the following functions with arrays containing up to 15 elements and assume there will be no significant bias with arrays containing up to 14 elements. If you work on a fixed-size problem requiring to compute many times this shuffle operation, you may want to try the following code which may be faster than other codes since it uses Math.random only once (it involves several copy operations however).

The following function will not be used, but I give it anyway; it returns the index of a given permutation of (0, 1, 2, …, n-1) according to the one to one mapping used in this message (the most natural one when enumerating permuations); it is intended to work with up to 16 elements:

function permIndex(p) {
    var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000];
    var tail = [];
    var i;
    if (p.length == 0) return 0;
    for(i=1;i<(p.length);i++) {
        if (p[i] > p[0]) tail.push(p[i]-1);
        else tail.push(p[i]);
    }
    return p[0] * fact[p.length-1] + permIndex(tail);
}

The reciprocal of the previous function (required for your own question) is below; it is intended to work with up to 16 elements; it returns the permutation of order n of (0, 1, 2, …, s-1):

function permNth(n, s) {
    var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000];
    var i, j;
    var p = [];
    var q = [];
    for(i=0;i<s;i++) p.push(i);
    for(i=s-1; i>=0; i--) {
        j = Math.floor(n / fact[i]);
        n -= j*fact[i];
        q.push(p[j]);
        for(;j<i;j++) p[j]=p[j+1];
    }
    return q;
}

Now, what you want merely is:

function shuffle(p) {
    var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000];
    return permNth(Math.floor(Math.random()*fact[p.length]), p.length).map(
            function(i) { return p[i]; });
}

It should work for up to 16 elements with a little theoretical bias (though unnoticeable from a practical point of view); it can be seen as fully usable for 15 elements; with arrays containing less than 14 elements, you can safely consider there will be absolutely no bias.

@Gershom Maes 2018-01-24 17:34:05

Definitely elegant!

@Daniel Martin 2015-06-25 15:25:25

I found this variant hanging out in the "deleted by author" answers on a duplicate of this question. Unlike some of the other answers that have many upvotes already, this is:

  1. Actually random
  2. Not in-place (hence the shuffled name rather than shuffle)
  3. Not already present here with multiple variants

Here's a jsfiddle showing it in use.

Array.prototype.shuffled = function() {
  return this.map(function(n){ return [Math.random(), n] })
             .sort().map(function(n){ return n[1] });
}

@WiredPrairie 2015-07-14 12:17:43

(I suspect it was deleted as it is a very inefficient way to randomize the array, especially for larger arrays... whereas the accepted answer, and a number of other clones of that answer randomize in-place).

@Daniel Martin 2015-07-14 18:54:30

Yeah, but given that the well-known wrong answer is still up with a bunch of votes, an inefficient but correct solution should at least be mentioned.

@WiredPrairie 2015-07-14 22:49:15

Which one is the "well-known wrong answer"?

@Daniel Martin 2015-07-14 22:58:40

[1,2,3,4,5,6].sort(function() { return .5 - Math.random(); }); - it doesn't give a random sort, and if you use it you can end up embarrassed: robweir.com/blog/2010/02/microsoft-random-browser-ballot.htm‌​l

@4castle 2017-11-10 14:39:53

You need to use .sort(function(a,b){ return a[0] - b[0]; }) if you want the sort to compare values numerically. The default .sort() comparator is lexicographic, meaning it will consider 10 to be less than 2 since 1 is less than 2.

@Daniel Martin 2017-11-10 14:56:44

@4castle Okay, I updated the code, but am going to revert it: the distinction between lexicographic order and numerical order doesn't matter for numbers in the range that Math.random() produces. (that is, lexicographic order is the same as numeric order when dealing with numbers from 0 (inclusive) to 1 (exclusive))

@Marcin Malinowski 2017-09-23 21:33:39

All the other answers are based on Math.random() which is fast but not suitable for cryptgraphic level randomization.

The below code is using the well known Fisher-Yates algorithm while utilizing Web Cryptography API for cryptographic level of randomization.

var d = [1,2,3,4,5,6,7,8,9,10];

function shuffle(a) {
	var x, t, r = new Uint32Array(1);
	for (var i = 0, c = a.length - 1, m = a.length; i < c; i++, m--) {
		crypto.getRandomValues(r);
		x = Math.floor(r / 65536 / 65536 * m) + i;
		t = a [i], a [i] = a [x], a [x] = t;
	}

	return a;
}

console.log(shuffle(d));

@Julian FARHI 2017-04-14 09:41:30

function shuffleArray(array) {
        // Create a new array with the length of the given array in the parameters
        const newArray = array.map(() => null);

        // Create a new array where each index contain the index value
        const arrayReference = array.map((item, index) => index);

        // Iterate on the array given in the parameters
        array.forEach(randomize);
        
        return newArray;

        function randomize(item) {
            const randomIndex = getRandomIndex();

            // Replace the value in the new array
            newArray[arrayReference[randomIndex]] = item;
            
            // Remove in the array reference the index used
            arrayReference.splice(randomIndex,1);
        }

        // Return a number between 0 and current array reference length
        function getRandomIndex() {
            const min = 0;
            const max = arrayReference.length;
            return Math.floor(Math.random() * (max - min)) + min;
        }
    }
    
console.log(shuffleArray([10,20,30,40,50,60,70,80,90,100]));

@ChristopheD 2010-03-15 22:41:10

The de-facto unbiased shuffle algorithm is the Fisher-Yates (aka Knuth) Shuffle.

See https://github.com/coolaj86/knuth-shuffle

You can see a great visualization here (and the original post linked to this)

function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}

// Used like so
var arr = [2, 11, 37, 42];
arr = shuffle(arr);
console.log(arr);

Some more info about the algorithm used.

@nikola 2010-03-16 08:02:36

... except that Math.random() is not random at all, and therefore the Fisher-Yates Shuffle will not randomly shuffle for sufficiently large sets. Just pointing this out in case someone attempts to the latter.

@Click Upvote 2010-03-17 00:09:56

@prometheus , what do you mean math.random is not random? why is it called math.random if it isnt?

@Derek Dahmer 2011-03-08 01:57:54

Here's a CoffeeScript implementation of the Fisher-Yates algorithm: gist.github.com/859699

@RobG 2011-06-08 07:21:31

The above answer skips element 0, the condition should be i-- not --i. Also, the test if (i==0)... is superfluous since if i == 0 the while loop will never be entered. The call to Math.floor can be done faster using ...| 0. Either tempi or tempj can be removed and the value be directly assigned to myArray[i] or j as appropriate.

@Phil H 2012-04-13 14:10:09

@prometheus, all RNGs are pseudo-random unless connected to expensive hardware.

@jm. 2012-04-18 21:29:23

Is @RobG right? Why don't you post another answer, RobG, instead of commenting this one.

@RobG 2012-04-19 00:58:02

@jm—About skipping zero? In the test while (--i) then if i = 1 when the loop starts, it will first be decremented to zero before being tested. The test will return false and so the loop isn't executed when i == 0. As for returning false if length is zero, that makes no sense at all - shuffling an empty array should just return the empty array. Another answer? There a zillion articles on the web about shuffling.

@RobG 2012-04-19 01:57:43

Oh, a good resource for shuffl, deal and draw is http://www.merlyn.demon.co.uk/js-shufl.htm

@theon 2012-07-20 12:57:47

@RobG the implementation above is functionally correct. In the Fisher-Yates algorithm, the loop isn't meant to run for the first element in the array. Check out wikipedia where there are other implementations that also skip the first element. Also check out this article which talks about why it is important for the loop not to run for the first element.

@joeytwiddle 2012-10-08 14:55:27

@RobG, @jm, Math.random() returns a number 0<=n<1. So after flooring Math.random() * ( 0 + 1 ) you'll always be swapping the first element with itself.

@RobG 2012-10-09 00:27:39

@joeytwiddle—|0 is just a different way to floor the value, happy with theon's explanation of why the first item should be skipped.

@frabcus 2013-04-04 15:07:58

Bad to give a particular implementation - should use one from a library.

@toon81 2013-04-24 09:19:48

@nikola "not random at all" is a little strong a qualification for me. I would argue that it is sufficiently random unless you're a cryptographer, in which case you're probably not using Math.Random() in the first place.

@theGrayFox 2014-06-14 21:07:03

Another good read for ensuring your algorithm is on point. cigital.com/papers/download/developer_gambling.php

@scaryguy 2015-11-22 11:30:49

Anyone who is going to use this implementation: DO NOT forget that this will CHANGE the given array! This will NOT create a new one and return a new array!..

@student 2016-01-26 15:59:15

@theon This returns duplicate results? Is my understanding wrong?

@theon 2016-01-29 10:29:21

@student It is a random shuffle. For an array with 4 elements, there are only 24 permutations. So for a given shuffle, another shuffle has a 1 in 24 chance of being the same. After 25 shuffles you are guaranteed to have at least one pair of duplicate results.

@JonathanHayward 2016-07-16 15:43:49

@nikola Remember, the importance of random number generation is too important to leave to chance.

@Jürgen Paul 2016-07-21 08:13:12

Does anyone know the inside-out version of this? en.wikipedia.org/wiki/…

@user993683 2017-01-20 01:11:54

Why arr = shuffle(arr); and not just shuffle(arr);? The array is passed in by reference so you can just keep the original reference.

@ffxsam 2017-02-12 07:18:52

Ugh, yoda (0 !== currentIndex).

@gman 2017-04-06 23:28:02

This would be faster with Math.random() * currentIndex | 0

@sonlexqt 2017-06-27 17:43:08

If you don't want to modify the old array, add var clone = array.slice(0); on the first line and then return the clone array instead.

@Alexander Mills 2018-07-13 03:51:26

An immutable version of this which does not manipulate the input would be good.

@Matt Ellis 2018-12-13 23:33:05

The visualization is a great addition to this answer; Mike Bostock is awesome!

@Laxman 2018-12-24 06:17:48

var currentIndex = array.length, temporaryValue, randomIndex; Can anyone explain what is happening in this line? I am new to javascript and could not understand how this assignment works.

@Lee Blake 2019-02-03 15:38:58

I'm using this function and it works to randomize the array, but when I run it twice on the same original array, I get the same output both times.

@Cezary Daniel Nowak 2017-02-22 10:51:00

I was thinking about oneliner to paste in console. All tricks with .sort was giving wrong results, here is my implementation:

 ['Bob', 'Amy', 'Joy'].map((person) => `${Math.random().toFixed(10)}${person}`).sort().map((person) => person.substr(12));

But don't use it in production code, it's not optimal and works with strings only.

@Gustavo Rodrigues 2017-08-15 19:43:57

It works with any kind of variable: array.map(e => [Math.random(), e]).sort((a, b) => a[0] - b[0]).map(e => e[1]) (but is not optimal).

@superluminary 2017-12-11 11:12:00

That is a very cute solution.

@Francisco Presencia 2016-11-12 09:40:19

I see no one has yet given a solution that can be concatenated while not extending the Array prototype (which is a bad practice). Using the slightly lesser known reduce() we can easily do shuffling in a way that allows for concatenation:

var randomsquares = [1, 2, 3, 4, 5, 6, 7].reduce(shuffle).map(n => n*n);

You'd probably want to pass the second parameter [], as otherwise if you try to do this on an empty array it'd fail:

// Both work. The second one wouldn't have worked as the one above
var randomsquares = [1, 2, 3, 4, 5, 6, 7].reduce(shuffle, []).map(n => n*n);
var randomsquares = [].reduce(shuffle, []).map(n => n*n);

Let's define shuffle as:

var shuffle = (rand, one, i, orig) => {
  if (i !== 1) return rand;  // Randomize it only once (arr.length > 1)

  // You could use here other random algorithm if you wanted
  for (let i = orig.length; i; i--) {
    let j = Math.floor(Math.random() * i);
    [orig[i - 1], orig[j]] = [orig[j], orig[i - 1]];
  }

  return orig;
}

You can see it in action in JSFiddle or here:

var shuffle = (all, one, i, orig) => {
    if (i !== 1) return all;

    // You could use here other random algorithm here
    for (let i = orig.length; i; i--) {
        let j = Math.floor(Math.random() * i);
        [orig[i - 1], orig[j]] = [orig[j], orig[i - 1]];
    }

    return orig;
}

for (var i = 0; i < 5; i++) {
  var randomarray = [1, 2, 3, 4, 5, 6, 7].reduce(shuffle, []);
  console.log(JSON.stringify(randomarray));
}

@Arthur2e5 2016-12-14 04:39:03

It seems that you're exchanging for too much times. With reduce you can totally perform a streaming "inside-out" Fisher-Yates that uses (acc, el) => { acc.push(el); let i = Math.floor(Math.random() * (acc.length)); [acc[i], acc[acc.length - 1]] = [acc[acc.length - 1], acc[i]]; return acc; } as the callback. (Adapted from public domain code on zhihu.)

@Tusko Trush 2016-10-17 18:13:49

the shortest arrayShuffle function

function arrayShuffle(o) {
    for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
    return o;
}

@Arthur2e5 2016-10-18 17:32:23

Apparently you are doing Sattolo's instead of Fisher-Yates (Knuth, unbiased).

@deadrunk 2013-09-06 04:55:22

[community edit: This answer is incorrect; see comments. It is being left here for future reference because the idea is not that rare.]

[1,2,3,4,5,6].sort(function() {
  return .5 - Math.random();
});

@Alex K 2013-10-28 09:49:32

i like this solution, enough to give a basic random

@radtad 2013-11-13 18:35:08

Downvoting as this isn't really that random. I don't know why it has so many upvotes. Do not use this method. It looks pretty, but isn't completely correct. Here are results after 10,000 iterations on how many times each number in your array hits index [0] (I can give the other results too): 1 = 29.19%, 2 = 29.53%, 3 = 20.06%, 4 = 11.91%, 5 = 5.99%, 6 = 3.32%

@deadrunk 2013-11-21 00:37:30

It's fine if you need to randomize relatively small array and not dealing with cryptographic things. I totally agree that if you need more randomness you need to use more complex solution.

@Blazemonger 2013-12-17 14:21:01

@spencercooly 2014-04-27 22:26:32

but it's very cute

@Ivan Yan 2014-05-13 08:42:58

@radtad I did a test, the result is 16%~17%

@MatsLindh 2014-09-10 14:07:44

The problem is that it's not deterministic, which will give wrong results (if 1 > 2 and 2 > 3, it should be given that 1 > 3, but this will not guarantee that. This will confuse the sort, and give the result commented by @radtad).

@Ultimater 2014-10-29 23:17:37

sort() for randomizing an array has a strong bias toward keeping each element in its initial starting position in addition to the edges of the array having slightly more bias than the middle: jsfiddle.net/rcmp0aLL

@Andre Figueiredo 2014-11-16 18:32:37

Would it be random enough if I put it in a loop to run x times? When x is the size of array?

@RobAu 2015-02-23 15:43:50

@Bergi 2015-04-03 20:48:46

@moeiscool 2016-04-26 02:53:30

best answer if you have jquery loaded already

@Luca C. 2016-07-29 07:29:08

ok, any efficent and correct method that is writable in 1/3 lines?

@Oriol 2016-08-03 14:25:12

@moeiscool How exactly is jQuery related to this answer?

@Master James 2017-03-22 12:18:54

It's pretty good. [1,2,3,4,5,6].sort(function() { return (.5 - Math.random() > .5 - Math.random()); }); If you also randomly reverse it.

@Master James 2017-03-22 12:25:13

var ans = [1,2,3,4,5,6,8,9,10,11,12,13,14,15,16].sort(function() { return (.5 - Math.random() > 0); }); if(.5 - Math.random() > 0) ans.reverse(); else ans;

@Master James 2017-03-22 12:32:41

No it doesn't really work with more then a handful, depends on randomizer partly too.

@Nisim Joseph 2017-12-06 14:09:09

why did you do (0.5 - random) ? it the same order and not doing any meaningful action. just want to understand that.

@bharal 2018-02-07 22:12:33

i like this, sometimes you don't want a cryptographically secure sort

@Ally 2018-03-18 00:58:54

It's true, wrote some code to test it codepen.io/anon/pen/BrLgyN?editors=0010

@Abdennour TOUMI 2016-07-25 14:51:23

$=(m)=>console.log(m);

//----add this method to Array class 
Array.prototype.shuffle=function(){
  return this.sort(()=>.5 - Math.random());
};

$([1,65,87,45,101,33,9].shuffle());
$([1,65,87,45,101,33,9].shuffle());
$([1,65,87,45,101,33,9].shuffle());
$([1,65,87,45,101,33,9].shuffle());
$([1,65,87,45,101,33,9].shuffle());

@Jacque Goupil 2016-07-26 05:03:48

This is very bad as the elements have a high probability of staying near their original position or barely moving from there.

@Abdennour TOUMI 2016-07-26 06:23:38

If it bad , chain it twice or more : array.shuffle().shuffle().shuffle()

@Jacque Goupil 2016-07-27 04:03:12

Repeating the call slightly reduces the probabilities of getting very similar results, but it doesn't make it a true random shuffle. In the worst case scenario, even an infinite number of calls to shuffle could still give the exact same array we started with. The Fisher-Yates algorithm is a much better and still efficient choice.

@Oriol 2016-08-02 17:39:15

Not the same awful answer again, please.

@BrunoLM 2015-12-20 04:15:25

With ES2015 you can use this one:

Array.prototype.shuffle = function() {
  let m = this.length, i;
  while (m) {
    i = (Math.random() * m--) >>> 0;
    [this[m], this[i]] = [this[i], this[m]]
  }
  return this;
}

Usage:

[1, 2, 3, 4, 5, 6, 7].shuffle();

@Oriol 2016-07-24 03:46:24

To truncate, you should use n >>> 0 instead of ~~n. Array indices can be higher than 2³¹-1.

@lukejacksonn 2017-05-11 12:28:24

Destructuring like this makes for such a clean implementation +1

@SynCap 2016-07-24 03:03:24

Ronald Fisher and Frank Yates shuffle

ES2015 (ES6) release

Array.prototype.shuffle2 = function () {
    this.forEach(
        function (v, i, a) {
            let j = Math.floor(Math.random() * (i + 1));
            [a[i], a[j]] = [a[j], a[i]];
        }
    );
    return this;
}

Jet optimized ES2015 (ES6) release

Array.prototype.shuffle3 = function () {
    var m = this.length;
    while (m) {
        let i = Math.floor(Math.random() * m--);
        [this[m], this[i]] = [this[i], this[m]];
    }
    return this;
}

@Oriol 2016-07-24 03:42:43

This is the same as BrunoLM's answer

@SynCap 2016-08-02 17:17:40

May be, but I don't thik so: 1) in my examples there are 2 - releases, one - for full understending, second - ready to use optimized version wich 2) not use low level ninja's tricks, 3) works in ANY environment with ES6. Please, don't mess the novices And, hmmm.. BrunoLM updated the answer, and now his anser is more powerful: in BrunoLM's code is not used Math but direct low level digital operations, so it's MUCH-MUCH faster. Now (after update) it's works correctly in ANY ES6 envs and strongly recomended, especially for big arrays. Thank u, Oriol.

@Andre Pastore 2016-06-16 20:34:54

Considering apply it to in loco or to a new immutable array, following other solutions, here is a suggested implementation:

Array.prototype.shuffle = function(local){
  var a = this;
  var newArray = typeof local === "boolean" && local ? this : [];
  for (var i = 0, newIdx, curr, next; i < a.length; i++){
    newIdx = Math.floor(Math.random()*i);
    curr = a[i];
    next = a[newIdx];
    newArray[i] = next;
    newArray[newIdx] = curr;
  }
  return newArray;
};

Related Questions

Sponsored Content

48 Answered Questions

76 Answered Questions

[SOLVED] How do I remove a particular element from an array in JavaScript?

  • 2011-04-23 22:17:18
  • Walker
  • 5490251 View
  • 6813 Score
  • 76 Answer
  • Tags:   javascript arrays

33 Answered Questions

[SOLVED] Create ArrayList from array

26 Answered Questions

[SOLVED] What does "use strict" do in JavaScript, and what is the reasoning behind it?

31 Answered Questions

[SOLVED] For-each over an array in JavaScript?

52 Answered Questions

[SOLVED] Create GUID / UUID in JavaScript?

  • 2008-09-19 20:01:00
  • Jason Cohen
  • 1404578 View
  • 3517 Score
  • 52 Answer
  • Tags:   javascript guid uuid

58 Answered Questions

[SOLVED] How do I redirect to another webpage?

30 Answered Questions

[SOLVED] How to append something to an array?

86 Answered Questions

[SOLVED] How do JavaScript closures work?

18 Answered Questions

[SOLVED] How do I empty an array in JavaScript?

  • 2009-08-05 09:08:39
  • amir
  • 2108091 View
  • 2199 Score
  • 18 Answer
  • Tags:   javascript arrays

Sponsored Content