数组乱序的正确姿势

underscore 中有一个函数,其作用是将数组乱序排序,实现如下:

// Shuffle a collection, using the modern version of the
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
// `shuffle` 函数。
_.shuffle = function(obj) {
  var set = isArrayLike(obj) ? obj : _.values(obj);
  var length = set.length;
  var shuffled = Array(length);
  for (var index = 0, rand; index < length; index++) {
    rand = _.random(0, index);
    if (rand !== index) shuffled[index] = shuffled[rand];
    shuffled[rand] = set[index];
  }
  return shuffled;
};

其中使用的数组乱序的算法是 Fisher–Yates shuffle。这是一个 O(n) 复杂度的随机排列数组元素的经典算法。

每次循环从前面的 index 个元素中随机选择一个元素 shuffle[rand]。将这个元素与第 index 个元素进行交换,直到 index == length 为止。这样对元素进行随机交换,对于每个结果所获得概率是均匀的。_.shuffle 方法是返回一个新的乱序数组,所以需要一个新的数组来存储。

对原有数组进行乱序:

function shuffle(arr) {
  var length = arr.length;
  for (var index = 0, rand; index < length; index ++) {
    rand = Math.floor(Math.random() * (length - 1));

    var temp = arr[rand];
    arr[rand] = arr[index];
    arr[index] = temp;
  }
  return arr;
}

More