十年踪迹的最新博客:5分钟现场撸代码——谈总结会抽奖程序,实际上就是一个洗牌算法,描述为从一个数组中随机抽取几个数出来,我之前写过的一个文章:js随机从数组中取出几个元素 正好符合上面的要求,看了他的代码,延伸出来的另外一种就是可以重复抽奖。学习一下,顺便复习一下以前写过的东西。
我原来简单的代码是这样子:
function getRandomArrayElements(arr, count) {
var shuffled = arr.slice(0), i = arr.length, min = i - count, temp, index;
while (i-- > min) {
index = Math.floor((i + 1) * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
}
return shuffled.slice(min);
}
var items = ['1','2','4','5','6','7','8','9','10'];
console.log( getRandomArrayElements(items, 4) );
逻辑:
1.首先从整个数组中抽取一个随机值,然后把这个值和最后面一个没有查过的项交换位置
2.循环遍历的结果就是所有随机值都放到最后面,循环次数为要取的随机数组长度。
3.最后把最后面的数组取出来就得到我们的随机数组了。
十年踪迹的代码使用到了ES6。
代码一:
const cards = Array(62).fill().map((_,i)=>i+1); //初始化一个 1~62 的数组 function draw(n = 1){ // 一次抽取 n 个,默认一次 1 个 var ret = []; for(var i = 0; i < n; i++){ let idx = Math.floor(cards.length * Math.random()); ret.push(...cards.splice(idx, 1)); } return ret; } console.log(draw(10)); //抽取一次,10个中奖者
1.其中ret.push(…cards.splice(idx,1));使用到了上一节讲到的ES6扩展符,这个会组合两个数组的值,
2.cards.splice(idx,1)返回的是删除的元素的数组,使用数组splice()方法,原数组cards也会发生变化,即原数组已经去掉了idx这个项。
3.接着循环的时候,cards.length缩小,idx,也会从剩下的项中取。
代码二:
代码二和代码三跟我最上面的做法差不多,通过洗牌算法
function draw(amount, n = 1){ const cards = Array(amount).fill().map((_,i)=>i+1); for(let i = amount - 1, stop = amount - n - 1; i > stop; i--){ let rand = Math.floor((i + 1) * Math.random()); [cards[rand], cards[i]] = [cards[i], cards[rand]]; } return cards.slice(-n); } console.log(draw(62, 10));
其中使用到了ES6的解构,解构提供了一个方便地从对象或数组中提取数据的方法。
let [x, y] = [1, 2]; // x = 1, y = 2 // ES5 equivalent: var arr = [1, 2]; var x = arr[0]; var y = arr[1];
使用这个语法,可以一次性给多个变量赋值。一个很好的附加用处是可以很简单地交换变量值:
let x = 1, y = 2; [x, y] = [y, x]; // x = 2, y = 1
代码四:
需求是可以分开多次来取值,则需要用到了构造函数来初始化,通过方法来获取值。
function Box(amount){ this.cards = Array(amount).fill().map((_,i)=>i+1); } Box.prototype.draw = function(n = 1){ let amount = this.cards.length, cards = this.cards; for(let i = amount - 1, stop = amount - n - 1; i > stop; i--){ let rand = Math.floor((i + 1) * Math.random()); [cards[rand], cards[i]] = [cards[i], cards[rand]]; } let ret = cards.slice(-n); cards.length = amount - n; return ret; } var box = new Box(62); console.log(box.draw(5), box.draw(5)); //一次取 5 个,取 2 次
这个没什么好说的,下面我附上一个我写的代码:
function RandomArr(amount) { this.arr = Array(amount).fill().map((_, i) = >i + 1); } RandomArr.prototype.getCount = function(count) { var arr = this.arr, len = arr.length, min = len - count, index; while (len-->min) { index = Math.floor((len + 1) * Math.random()); [arr[index], arr[len]] = [arr[len], arr[index]]; } var ret = arr.slice(min); arr.length = min; return ret } var rand = new RandomArr(62); console.log(rand.getCount(4), rand.getCount(6));
有一些东西,叫我十分钟现场写出来,可能写不出来吧。看来还是要多掌握基础的东西。比如这个洗牌算法:
function shuffle(array) {
var currentIndex = array.length
, temporaryValue
, randomIndex
;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
本文纯粹水文一篇,欢迎到十年踪迹的原文看他的思路:https://www.h5jun.com/post/luckey-draw-in-5-minutes.html