JavaScript洗牌算法之重复抽奖
十年蹤跡的最新博客: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
總結
以上是生活随笔為你收集整理的JavaScript洗牌算法之重复抽奖的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 20个经典寓言故事超短
- 下一篇: 甚感欣慰是什么意思