Skip to content

Instantly share code, notes, and snippets.

@vjeux
Forked from WebReflection/LICENSE.txt
Created May 22, 2011 19:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save vjeux/985755 to your computer and use it in GitHub Desktop.
Save vjeux/985755 to your computer and use it in GitHub Desktop.
140byt.es -- Array Shuffle

Shuffle an array in-place using Fisher–Yates shuffle

var shuffle = function(a,b,c){for(b=a.length;b;c=0|b*Math.random(),a[c]=[a[--b],a[b]=a[c]][0]);}

var a = [1, 2, 3, 4, 5, 6, 7];

shuffle(a); console.log(a);
// [2, 3, 6, 7, 4, 1, 5]

shuffle(a); console.log(a);
// [3, 6, 5, 2, 1, 4, 7]
function // Shuffle
(a, // Array
// Local variables:
i, // Element iterator
j) // Element to swap
{
for (
i = a.length; // Start at the end
i; // Iterate over the whole array except the first element
j = 0 | // Pick (Math.floor)
i * Math.random(), // A random position before the current element
// --i
// Swap a[i] and a[j]
a[j] = [a[--i], a[i] = a[j]] [0]
);
}
function(a,b,c){for(b=a.length;b;c=0|b*Math.random(),a[c]=[a[--b],a[b]=a[c]][0]);}
Copyright (c) 2011 Christopher Chedeau, http://blog.vjeux.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
{
"name": "array_shuffle",
"description": "Shuffle an Array",
"keywords": [
"140bytes",
"shuffle",
"array"
]
}
@jed
Copy link

jed commented May 22, 2011

almost there. you just have to:

  • fork the master gist
  • add your code, don't forget to change the LICENSE
  • rename your arguments to a,b,c

@vjeux
Copy link
Author

vjeux commented May 22, 2011

What is the rationale behind renaming the arguments? It makes little sense to renamed them into a, b, c as they are not intuitive to read :x

@jed
Copy link

jed commented May 22, 2011

this is just my opinion, but they're not intuitive to read as they are now. once you have a whole bunch of tweet-length functions, it's easier to follow the logic if it's positional.

@vjeux
Copy link
Author

vjeux commented May 22, 2011

Okay, that should be it now :)

@maettig
Copy link

maettig commented Dec 12, 2011

@mattpass will donate 3 Euro to charity for each character golfed away from this function. We found a solution worth 78 81 Euro (thanks to tsaniel and p01) but I'm not sure if using sort is acceptable. What do you think?

function(a){a.sort(function(){return.5-Math.random()})}

This works perfectly for all kinds of arrays but is about 5 times slower than the original Fisher–Yates implementation.

Edit: About being original. Come on. I'm sure this was done a million times before. Nevertheless, I came up with the idea myself without using Google.

@tsaniel
Copy link

tsaniel commented Dec 12, 2011

My early snippet:
https://gist.github.com/1345090

function(a){with(a)for(a=length;a;)push(splice(Math.random()*a--,1)[0])}

Updated.

@tsaniel
Copy link

tsaniel commented Dec 12, 2011

By the way, maybe we can save 1 byte for the sort version by

function(a){a.sort(function(){return.5-Math.random()})}

?

@maettig
Copy link

maettig commented Dec 12, 2011

@tsaniel, I didn't know that, thanks. I tried function f(a,b){return b?.5-Math.random():a.sort(f)} (edit: fixed, thanks @vjeux) but this will turn into an endless loop if the array contains something that coerces to false.

@p01
Copy link

p01 commented Dec 12, 2011

We can save one more byte on the short version ;)

function c(a,b){return b||a.sort(c)&&.5-Math.random()}

EDIT: Nice twist @maettig also I didn't think of the edge case.

@vjeux
Copy link
Author

vjeux commented Dec 12, 2011

@maettig Shouldn't the condition be inverted?

function c(a,b){return b?Math.random()-.5:a.sort(c)}

a=[1, 2, 3, 4, 5, 6, 7, 8]
c(a)
> [1, 3, 4, 5, 7, 6, 2, 8]

@tsaniel
Copy link

tsaniel commented Dec 12, 2011

c([1,0])
> TypeError: Object 1 has no method 'sort'

@maettig
Copy link

maettig commented Dec 12, 2011

I'm afraid all of this will turn into an endless loop if called with e.g. [1,0,2] (or will fail as mentioned by @tsaniel above). Here is an other idea to save a byte, but this also shuffles nested arrays (except for the last one): function f(a){a.pop&&a.sort(f);return.5-Math.random()}

@vjeux
Copy link
Author

vjeux commented Dec 12, 2011

@maettig Same byte count but returns the array instead of a random number. However it doesn't compare well nested arrays.

function c(a){return a.pop?a.sort(c):Math.random()-.5}

@vjeux
Copy link
Author

vjeux commented Dec 12, 2011

@maettig, Looks like I wasn't clear. My version does not have the same "semantics" as yours. It doesn't shuffle the inner arrays but instead returns an invalid value in the comparison function (a.sort().toString()).

@maettig
Copy link

maettig commented Dec 12, 2011

@vjeux, I'm sorry, I don't understand. The version function c(a){return a.pop?a.sort(c):Math.random()-.5} does shuffle the inner arrays, but not the outer one (because of the invalid value). Calling var a=[[1,2],[3,4],[5,6]]; a=shuffle(a); changes the array to [[2,1],[4,3],[5,6]], for example, no matter if it's called with or without a=. My version always returns a random number and therefor shuffles the outer array too. But it's a bad implementation anyway, it's not worth the trouble for saving a single byte. ;-)

@vjeux
Copy link
Author

vjeux commented Dec 12, 2011

Yes, you are right! I spoke too fast :) Sorry

@maettig
Copy link

maettig commented Dec 15, 2011

I played around with pseudorandom numbers and it works but is longer than simply calling Math.random(). And it's not self contained, it needs to be called with an initial value for the generator, e.g. shuffle(a, new Date().getTime()). Without, it will create the same result every time.

function(a,b){a.sort(function(){return.5-(b=b*7%99)%2})}

In the end I came up with a solution worth 108 Euro. No, not really. It's clearly a fake but it kind of shuffles all types of arrays. For example, the array [1,2,3,4,5,6,7,8,9,10] becomes [2,7,8,3,9,6,4,10,1,5]. Looks random but isn't. It's the same every time. The function also accepts an initial value but since it's boolean there are only two possibilities how a specific array is ordered.

function(a,b){a.sort(function(){return b=!b})}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment