【青训营】写好JS——保证正确

简介: 【青训营】写好JS——保证正确

在实际项目当中我们经常会出现以下问题:


  • 代码可以跑通,但是业务上总出bug
  • 业务上没有异常,但是代码执行的过程中总是出现异常
  • 代码没问题,测试也没问题,但不能保证正确性,或者说保证公平


一个例子:洗牌



如果让你实现一个洗牌算法,你会怎么实现?


Math.random()


如果使用Math.random()我会这样实现:


const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
function shuffle(cards) {
  return [...cards].sort(() => 
    Math.random() > 0.5 ? -1 : 1
  )
}
console.log(shuffle(cards))
复制代码


写完多运行几次:


image.png


可以看出确实是洗牌了,但是这样随机出来的就公平吗?我们测试一下。


测试


增大测试次数为一百万次,然后记录每个位置出现的数字之和,如果公平的话,这个结果应该都很接近。


const result = Array(10).fill(0);
for(let i = 0; i < 1000000; i++) {
  const c = shuffle(cards);
  for(let j = 0; j < 10; j++) {
    result[j] += c[j];
  }
}
console.log(result);
复制代码


测试结果如图:


image.png


可以看到每个位置的数字之和差距极大,并没有出现接近的情况,所以这个算法确实是一个不公平的算法。


改进


之前的算法之所以出现问题,是因为sort()导致交换的位置不够随机。


我们可以使用一个经典算法进行改进(如果学过概率论应该很熟悉,就是摸球拿了不放回去):


  • 每次随机抽取一张放到最后
  • 剩下的重复第一步即可



image.png

image.png

image.png


而且这个算法可以通过数学归纳法证明每个位置概率都是相等的,写成代码就是这样的:


const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function shuffle(cards) {
  const c = [...cards];
  for (let i = c.length; i > 0; i--) {
    const pIdx = Math.floor(Math.random() * i);
    [c[pIdx], c[i - 1]] = [c[i - 1], c[pIdx]];
  }
  return c;
}
console.log(shuffle(cards));
复制代码


还用上面的测试代码测试一下正确性:


image.png


可以看出来数字都很接近,这个算法就是我们想要的保证正确(公平)的代码。


而且这样写还有一个好处就是:当只需要抽取少量随机牌时,我们并不需要把每张牌都随机一遍(也就是完全洗一遍),性能显然更高。


目录
相关文章
|
3月前
|
存储 缓存 自然语言处理
深入理解JS | 青训营笔记
深入理解JS | 青训营笔记
38 0
|
数据采集 缓存 负载均衡
【青训营】-🥝Node.js基础入门
【青训营】-🥝Node.js基础入门
169 3
【青训营】-🥝Node.js基础入门
|
监控 JavaScript 前端开发
Node.js入门 | 青训营
Node.js入门 | 青训营
127 0
Node.js入门 | 青训营
|
算法 JavaScript
【青训营】写好JS——学好算法
【青训营】写好JS——学好算法
88 0
【青训营】写好JS——学好算法
|
JavaScript 前端开发
【青训营】写好JS——做好抽象
【青训营】写好JS——做好抽象
139 0
【青训营】写好JS——做好抽象
|
JavaScript
【青训营】写好JS——写代码最应该关注什么?
【青训营】写好JS——写代码最应该关注什么?
116 0
【青训营】写好JS——写代码最应该关注什么?
|
JavaScript 测试技术
【青训营】写好JS——过程抽象
【青训营】写好JS——过程抽象
248 0
【青训营】写好JS——过程抽象
|
JavaScript 前端开发 API
【青训营】写好JS——组件封装(下)
【青训营】写好JS——组件封装(下)
272 0
【青训营】写好JS——组件封装(下)
|
JavaScript 前端开发 API
【青训营】写好JS——组件封装(上)
【青训营】写好JS——组件封装(上)
234 0
【青训营】写好JS——组件封装(上)
|
JavaScript 前端开发
【青训营】写好JS——各司其责
【青训营】写好JS——各司其责
92 0
【青训营】写好JS——各司其责