js 数组随机数 数组洗牌

这次分享一个随机数组洗牌的一个算法,让你得到随机数组。

假如1个数组的值是这样的:

const arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

因为在实践操作中,在网上搜可以搜到一大堆随机的这些代码。但是实际上究竟是不是完全随机,效率和兼容性都有待测试,如果有这方面的需求 可以尝试以下的代码。具体这个代码的算法是如何得出的,是否是完全随机,可以看看下面文章。

  1. 德州扑克
  2. 如何随机化(shuffle)一个JavaScript数组?
  3. 费雪耶茨洗牌

下面是具体实现的代码

Array.prototype.shuffle = function() {
  let m = this.length, i;
  while (m) {
    i = (Math.random() * m--) >>> 0;
    [this[m], this[i]] = [this[i], this[m]]
  }
  return this;
}

上面代码对数组原型进行了扩展,加了 shuffle 方法 通过数组调用的方式完成的随机数组项的重组. 让我们来看下实现的过程。
首先通过数组调用
Math.random()是令系统随机选取大于等于 0.0 且小于 1.0 的伪随机 double 值

arr.shuffle(); 

进入到函数后 分别定义了 m 变量和 i 变量;
m为当前数组的长度, i先声明 ,以便在下面while中使用。
通过while循环进行遍历;

 i = (Math.random() * m--) >>> 0;

大家看到上面这行代码代码时可能对后面的表达式稍微有点疑惑:
Math.random()是随机选取大于等于 0.0 且小于 1.0 的伪随机 double 值 这个有点js基础的都知道
主要对于 >>> 0;会有点迷惑 那么他们是什么呢?
图片描述

通过上述我们可以看到 这个 >>> 是无符号右移
但是位移0位有什么作用呢?
在 stackoverflow 查了一些资料 引入里面一个 高票的回答
原来移位操作符在移位操作前做了两种类似转换:

  1. 将不是number类型的数据转换为number,
  2. 将number转换为无符号的32bit数据,也就是Uint32类型。这些与移位的位数无关,移位0位主要就是用了js的内部特性做了前两种转换。

我们知道Uint32如果不能转换为Number,那就为0,如果为非整数,先转换为整数;

x >>> 0本质上就是保证x有意义(为数字类型),且为正整数,在有效的数组范围内(且在无意义的情况下缺省值为0;
知道了这些后我们就继续下面代码的分析
首先Math.random()会返回一个0到1之前的随机数 假设我们返回的是0.999... 那么我们在第一次循环的 m--后的值为6 那我们得到值就是 5.994.... 通过无符号右移 得到一个整数值为 5,也就是 i值现在是5 开始执行下列代码:

[this[m], this[i]] = [this[i], this[m]]

上面代码为es6新语法 解构赋值 ,通过上边代码 我们得到值 m 为6 i为5,上面代码实际实现了 下标为m的值和下标为i的值位置的互换。
后面依次执行进行循环...
因为每次循环i的值不断变化 所以位置的互换也在不断变化。 循环一圈后就形成了对数组的洗牌。
最后返回洗牌后的数组。

如果你遇到类似的需求,那就快拷贝代码,用一个数组尝试一下吧~

posted on 2022-11-29 21:11  zhangzongshan  阅读(126)  评论(0编辑  收藏  举报

导航