基于JavaScript開發(fā)一個(gè)有趣的分組抽簽小程序
前言
今天我要和大家分享一個(gè)非常有用的js算法:分組抽簽。在團(tuán)隊(duì)合作開發(fā)中,經(jīng)常需要將團(tuán)隊(duì)成員分組,來完成各自的任務(wù)。而抽簽的方式自然是最公平、最簡單的方法之一。
需求分析
在介紹具體的抽簽算法之前,我們先來分析一下這個(gè)問題的需求。我們需要從團(tuán)隊(duì)成員列表中隨機(jī)抽取若干人,并將這些人分配到不同的組中。那么,如何才能確保分組的公平性呢?
公平性的要求
首先,我們需要確保每個(gè)人只會(huì)被抽中一次,避免出現(xiàn)某個(gè)人被抽到多個(gè)組的情況。其次,我們需要盡可能地讓每個(gè)組的人數(shù)相近,以確保各組的工作量基本相同。
算法設(shè)計(jì)思路
在滿足上述需求的前提下,我們可以通過以下算法來進(jìn)行分組抽簽:
1.將團(tuán)隊(duì)成員列表隨機(jī)排序。
2.根據(jù)分組的數(shù)量,計(jì)算每個(gè)組應(yīng)該包含的人數(shù),記為baseNum。
3.依次遍歷團(tuán)隊(duì)成員列表,將每個(gè)人放入對(duì)應(yīng)的組中。具體操作步驟如下:
- 如果該人已經(jīng)被分配了組,直接跳過。
- 如果該人所在的組未滿員,將其加入該組,并標(biāo)記為已分組。
- 如果該人所在的組已滿員,尋找下一個(gè)未滿員的組,將其加入該組,并標(biāo)記為已分組。如果沒有未滿員的組,則隨機(jī)選擇一個(gè)非自己所在組的未滿員組,將其加入該組,并標(biāo)記為已分組。
通過以上闡述可知,核心的算法思路是要隨機(jī)排序、盡量平均分組并避免同一人多次參與?,F(xiàn)在我們開始著手編寫這個(gè)算法。
開始編碼
隨機(jī)排序
為了實(shí)現(xiàn)隨機(jī)排序,我們可以先將團(tuán)隊(duì)成員數(shù)組進(jìn)行淺拷貝,然后使用Array.sort()方法來進(jìn)行排序,代碼如下:
function shuffle(array) { const arr = [...array]; // 進(jìn)行淺拷貝 for (let i = arr.length - 1; i > 0; i--) { // 遍歷數(shù)組元素 const j = Math.floor(Math.random() * (i + 1)); // 生成隨機(jī)下標(biāo) [arr[i], arr[j]] = [arr[j], arr[i]]; // 交換位置 } return arr; // 返回排序后的數(shù)組 }
該方法接受一個(gè)數(shù)組作為參數(shù),返回亂序排列之后的新數(shù)組。
盡可能平均分組
為了實(shí)現(xiàn)盡量平均分組,我們可以使用Math.ceil()方法來向上取整,保證每個(gè)組的人數(shù)不少于baseNum。代碼如下:
const team = ['張三', '李四', '王五', '趙六', '錢七', '孫八']; // 假設(shè)有6名成員 const groupNum = 3; // 定義需要抽幾組 const baseNum = Math.ceil(team.length / groupNum); // 計(jì)算每組包含的人數(shù) console.log(baseNum); // 輸出2
避免同一人多次參與
為了避免同一個(gè)人多次參與分組,我們需要給已經(jīng)分配了組的成員打上已分組的標(biāo)記,這樣在后續(xù)循環(huán)中就可以跳過已經(jīng)分配了組的成員。代碼如下:
const team = ['張三', '李四', '王五', '趙六', '錢七', '孫八']; // 團(tuán)隊(duì)成員數(shù)組 const groupNum = 3; // 分組數(shù) const baseNum = Math.ceil(team.length / groupNum); // 計(jì)算每組需要包含多少人 const shuffledTeam = shuffle(team); // 亂序排列團(tuán)隊(duì)成員 let assignedCount = 0; // 計(jì)數(shù)器,記錄已分配的人數(shù) let groups = []; // 定義一個(gè)空數(shù)組,用來存放每個(gè)分組的成員 // 遍歷隨機(jī)排序后的團(tuán)隊(duì)成員列表,進(jìn)行分組 shuffledTeam.forEach(member => { if (member.assigned) return; // 如果該成員已被分配,則跳過 for (let i = 0; i < groupNum; i++) { const group = groups[i] || []; // 如果當(dāng)前分組未定義,則將其初始值設(shè)為空數(shù)組 if (group.length < baseNum && !group.includes(member)) { // 如果該分組未滿員,并且該成員沒有被分配到其他組內(nèi) group.push(member); // 將該成員加入當(dāng)前分組 member.assigned = true; // 給該成員打上已分組標(biāo)記 assignedCount++; // 記錄已分配人數(shù) groups[i] = group; // 將該分組重新賦值給原數(shù)組 break; // 遍歷下一個(gè)成員 } } });
在上述代碼中,我們使用了一個(gè)名為assigned的屬性作為已分組標(biāo)記。每位成員在初始化時(shí)都未被分組,因此默認(rèn)為undefined。當(dāng)某位成員被分配到某個(gè)組內(nèi)后,我們就會(huì)將其assigned屬性設(shè)置為true,以避免重復(fù)分組。
上手練習(xí)
接下來讓我們來進(jìn)行一個(gè)簡單的實(shí)現(xiàn)過程和實(shí)驗(yàn),使大家更加深入理解如何實(shí)現(xiàn)一個(gè)前端抽簽小程序。
HTML結(jié)構(gòu)
首先,我們需要先創(chuàng)建一些基本的HTML結(jié)構(gòu),來讓用戶輸入團(tuán)隊(duì)成員信息,并設(shè)定分組數(shù)量和按鈕控制器:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>分組抽簽小程序</title> <script src="main.js"></script> </head> <body> <h1>分組抽簽小程序</h1> <form id="form"> <div> <label for="members">團(tuán)隊(duì)成員:</label> <textarea id="members" name="members" placeholder="請用英文半角逗號(hào)分隔不同的成員"></textarea> </div> <div> <label for="groups">分組數(shù)量:</label> <input type="number" id="groups" name="groups" value="2" min="2"> </div> <button type="submit">開始抽簽</button> </form> <div id="result"></div> </body> </html>
JS代碼
在JavaScript中,我們需要編寫3個(gè)函數(shù)來實(shí)現(xiàn)這個(gè)小程序:一是獲取關(guān)鍵DOM元素(getInputs),二是執(zhí)行抽簽操作并輸出結(jié)果(drawLots),三是事件監(jiān)聽邏輯(handleSubmit)。代碼如下:
// 獲取form表單輸入值的函數(shù) function getInputs(form) { const members = form.members.value.trim().split(/[,\n]/).map(m => m.trim()).filter(m => m); // 轉(zhuǎn)換成數(shù)組格式,并清理空格和空白行 const groups = +form.groups.value; // 輸入分組數(shù)量 return { members, groups }; } // 主要操作函數(shù) function drawLots(members, groups) { const baseNum = Math.ceil(members.length / groups); // 計(jì)算每組包含多少成員 const shuffledMembers = shuffle(members); // 將成員數(shù)組隨機(jī)排序 let assignedCount = 0; // 計(jì)數(shù)器,記錄已分配的人數(shù) let result = ''; // 定義一個(gè)空字符串,用來存放抽簽結(jié)果 let groupsRes = []; // 定義一個(gè)空數(shù)組,用來存放每個(gè)分組的成員 // 遍歷隨機(jī)排序后的成員列表,進(jìn)行分組 shuffledMembers.forEach(member => { if (member.assigned) return; // 如果該成員已被分配,則跳過 for (let i = 0; i < groups; i++) { const group = groupsRes[i] || []; // 如果當(dāng)前分組未定義,則將其初始值設(shè)為空數(shù)組 if (group.length < baseNum && !group.includes(member)) { // 如果該分組未滿員,并且該成員沒有被分配到其他組內(nèi) group.push(member); // 將該成員加入當(dāng)前分組 member.assigned = true; // 給該成員打上已分組標(biāo)記 assignedCount++; // 記錄已分配人數(shù) groupsRes[i] = group; // 將該分組重新賦值給原數(shù)組 break; // 遍歷下一個(gè)成員 } } }); // 輸出結(jié)果 groupsRes.forEach((group, index) => { result += `<h3>第${index+1}組:</h3><ul>`; group.forEach(member => result += `<li>${member}</li>`); result += `</ul>`; }); document.getElementById('result').innerHTML = result; // 修改DOM節(jié)點(diǎn)內(nèi)容,將抽簽結(jié)果展示給用戶 } // 監(jiān)聽表單提交事件 function handleSubmit(event) { event.preventDefault(); const form = event.currentTarget; const { members, groups } = getInputs(form); if (members.length === 0) { alert('請輸入團(tuán)隊(duì)成員!'); return; } drawLots(members, groups); } document.getElementById('form').addEventListener('submit', handleSubmit); // 掛載監(jiān)聽函數(shù)
代碼中包括了淺層的代碼實(shí)現(xiàn)方法,只要牢記三個(gè)階段內(nèi)容,便可輕松完成這個(gè)小程序。
以上就是基于JavaScript開發(fā)一個(gè)有趣的分組抽簽小程序的詳細(xì)內(nèi)容,更多關(guān)于JavaScript分組抽簽程序的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于JS實(shí)現(xiàn)密碼框(password)中顯示文字提示功能代碼
這篇文章主要介紹了實(shí)現(xiàn)密碼框(password)中顯示文字提示功能代碼,在項(xiàng)目開發(fā)中經(jīng)常會(huì)用到,需要的朋友可以參考下2016-05-05JavaScript頁面實(shí)時(shí)顯示當(dāng)前時(shí)間實(shí)例代碼
最近因?yàn)轫?xiàng)目需要,有個(gè)需求是讓實(shí)時(shí)顯示當(dāng)前時(shí)間,然后想想這不簡單嗎,自己就動(dòng)手敲代碼,但是發(fā)現(xiàn)一個(gè)問題,通過getMonth()得到月份,總是會(huì)比當(dāng)前月份少1,深深覺得實(shí)踐出真知啊…之前覺得Date對(duì)象挺簡單的,有很多細(xì)節(jié)都沒有注意。下面這篇文章就給大家詳細(xì)介紹下。2016-10-10Chart.js 輕量級(jí)HTML5圖表繪制工具庫(知識(shí)整理)
這篇文章主要介紹了Chart.js 輕量級(jí)HTML5圖表繪制工具庫,Chart.js基于HTML5 canvas技術(shù)支持所有現(xiàn)代瀏覽器,并且針對(duì)IE7/8提供了降級(jí)替代方案,感興趣的小伙伴們可以參考一下2018-05-05根據(jù)選擇不同的下拉值出現(xiàn)相對(duì)應(yīng)的文本輸入框
根據(jù)用戶選擇不同的下拉值,出現(xiàn)相應(yīng)的文本輸入框,在某些情況下比較實(shí)用,本文為大家寫了個(gè),有需求的朋友可以參考下2013-08-08微信小程序之導(dǎo)航滑塊視圖容器功能的實(shí)現(xiàn)代碼(簡單兩步)
這篇文章主要介紹了微信小程序之導(dǎo)航滑塊視圖容器功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06JS動(dòng)態(tài)計(jì)算移動(dòng)端rem的解決方案
移動(dòng)設(shè)備分辨率五花八門雖然我們可以通過CSS3的media query來實(shí)現(xiàn)適配,但是這種做法并不能適配所有設(shè)備,這篇文章主要介紹了js動(dòng)態(tài)計(jì)算移動(dòng)端rem的解決方案,非常不錯(cuò),感興趣的朋友一起看看吧2016-10-10javascript面向?qū)ο笾畉his關(guān)鍵詞用法分析
這篇文章主要介紹了javascript面向?qū)ο笾畉his關(guān)鍵詞用法分析,以實(shí)例形式分析了在不同場合下this使用中的特性及相關(guān)使用技巧,需要的朋友可以參考下2015-01-01