Random but just in Chrome

2019-02-25 21:12发布

问题:

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.

回答1:

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.



回答2:

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.



回答3:

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)