基于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="請(qǐng)用英文半角逗號(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('請(qǐng)輸入團(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分組抽簽程序的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于JS實(shí)現(xiàn)密碼框(password)中顯示文字提示功能代碼
這篇文章主要介紹了實(shí)現(xiàn)密碼框(password)中顯示文字提示功能代碼,在項(xiàng)目開發(fā)中經(jīng)常會(huì)用到,需要的朋友可以參考下2016-05-05
JavaScript頁面實(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-10
Chart.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-06
JS動(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-10
javascript面向?qū)ο笾畉his關(guān)鍵詞用法分析
這篇文章主要介紹了javascript面向?qū)ο笾畉his關(guān)鍵詞用法分析,以實(shí)例形式分析了在不同場合下this使用中的特性及相關(guān)使用技巧,需要的朋友可以參考下2015-01-01
前端GET/POST請(qǐng)求下載文件多種方式代碼示例
文件都是通過接口獲取的,前端通過調(diào)用接口將接口返回的文件下載,下面這篇文章主要給大家介紹了關(guān)于前端GET/POST請(qǐng)求下載文件的多種方式,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06

