这个W3Schools代码如何使用.sort()改组数组?

时间:2017-05-22 02:30:14

标签: javascript

此代码段来自w3schools JavaScript section。我想找出什么

points.sort( function(a, b) {
  return 0.5 - Math.random()
});

从下面的代码做。我知道它试图对存储在名为points的数组中的数字进行随机排序,但我不明白如何使用return 0.5 - Math.random()实现它。

我知道random会返回0到1之间的数字(不包括1)。 我认为从那个数字中减去0.5,但我不确定从这里发生了什么。你能不能给我一步一步的解释?

<!DOCTYPE html>
<html>
<body>

  <p>Click the button (again and again) to sort the array in random order.</p>

   <button onclick="myFunction()">Try it</button>

   <p id="demo"></p>

   <script>
     var points = [40, 100, 1, 5, 25, 10];
     document.getElementById("demo").innerHTML = points;    

     function myFunction() {
      points.sort(function(a, b){return 0.5 - Math.random()});
      document.getElementById("demo").innerHTML = points;
     }
   </script>

 </body>

2 个答案:

答案 0 :(得分:3)

将回调传递给返回随机值的Array#sort()是一个坏主意; ECMAScript规范不保证在这种情况下会发生什么。每MDN

  当给定一对特定元素a和b作为其两个参数时,

compareFunction(a, b)必须始终返回相同的值。如果返回不一致的结果,则排序顺序未定义。

根据the spec itself

  

如果 comparefn 不是未定义并且不是此数组元素的一致比较函数(见下文),则排序顺序是实现定义的。

该问题的W3Schools代码明显被破坏;它没有公平地改变阵列,至少在Chrome中是这样。让我们尝试运行它一百万次并计算在#34; shuffling&#34;之后每个值出现在数组中的最终位置的频率:

function shuffleAndTakeLastElement() {
    var points = [40, 100, 1, 5, 25, 10];
    return points.sort(function(a, b){return 0.5 - Math.random()})[5];
}
results = {};
for (var point of [40, 100, 1, 5, 25, 10]) results[point] = 0;
for (var i = 0; i < 1000000; i++) results[shuffleAndTakeLastElement()]++;
console.log(results);

我在Chrome中获得以下数量:

{1: 62622, 5: 125160, 10: 500667, 25: 249340, 40: 31057, 100: 31154}

注意数字10在阵列结束位置结束的可能性大约是数字40或100的16倍。这不是一次公平的洗牌!

从这个故事中吸取一些道德:

  • 您应该运行大量测试并查看结果,以帮助确认任何随机性算法是否公平。
  • 即使您从一个公平的随机来源开始,也很容易意外地编写有偏见的算法。
  • 对于改组数组,请使用Lodash's _.shuffle methodHow to randomize (shuffle) a JavaScript array?中的一种方法。
  • 永远不要相信你在W3School上读到的任何内容,因为它们很糟糕并且充满了错误。

答案 1 :(得分:2)

sort回调应该返回值&lt; 0,0或&gt; 0以指示第一个值是否低于,等于或高于第二个值; sort使用它来对值进行排序。 0.5 - Math.random()随机返回介于-0.5和0.5之间的值,满足预期的返回值,从而产生一个基本上随机混乱的数组。

请注意,这不应该是改组的首选方法;由于返回值是随机的而不是内部一致的(例如,它告诉sort foo < barbar < bazfoo > baz),它可能会使Javascript的排序算法效率非常低。例如,Fisher-Yates shuffle非常简单,可能效率更高。