I've this function to create a random range of numbers.
function randomRange(min, max) {
return (new Array(++max-min))
.join('.').split('.')
.map(function(v,i){ return min+i; })
.sort(function(){ return 0|Math.random()*max; });
}
It works perfect but only in Chrome. All other browsers have very little variation for some reason...
I've a simple demo here so you can see the difference http://jsfiddle.net/elclanrs/zZRda/.
As you can see the order of numbers in Chrome is mostly random but in other browsers there's not much variation, only a few numbers change place but it all looks almost the same.
Now check http://jsbin.com/iyalax/3/edit in Chrome and other browsers and you'll see the difference very clearly.
Any ideas why this is happening?
Edit: I've another randomRange
function that works fine in all browsers, it's just longer and uglier, check http://jsbin.com/iyalax/4/edit to see the difference.
According to MDN,
array.sort([compareFunction])
If compareFunction(a, b) returns 0, leave a and b unchanged with
respect to each other, but sorted with respect to all different
elements. Note: the ECMAscript standard does not guarantee this
behaviour, and thus not all browsers (e.g. Mozilla versions dating
back to at least 2003) respect this.
You can try
.sort(function(){ return Math.random()*2-1; })
All you're trying to do here is to return a number that is either greater, less than or equal to 0.
This may due to the implementation of sort() method between explorers. From the fact that I've seen so far, I guess maybe the Chrome always use non-stable sort(e.g quicksort) when do sorting, while the others use stale sort(e.g bubble sort) when the input size is small.
At first, the input(created originally from new Array(..)
) is already sorted; and the function(){ return 0|Math.random()*max; }
will always return a non-negative, which indicates that a>=b(or a<=b, I am not sure)? So, when I try to dig this out, I find that the sort behavior is different between Chrome and IE(version 9).
In IE: [1,2,3].sort( function(){return 1} )
gives out [1,2,3]
; but in Chrome, the result is [3,2,1]
, so I believe this maybe the real factor.
So, as a conclusion, I would like to use .sort(function(){ return (0|Math.random()*max)-max/2; })
instead.
Problem solved! I found a pretty sweet solution at Hacker News, it works perfect in all browsers now:
function randomRange(min, max) {
return (new Array(++max-min))
.join('.').split('.')
.map(function(v,i){ return min+i; })
.map(function(v) { return [Math.random(), v]; })
.sort().map(function(v) { return v[1]; });
}
Demo: http://jsbin.com/iyalax/9/edit (click "Run with JS" if you can't see the image)