如何在JavaScript/TypeScript中实现人员向活动的均匀分配
人员均等分配活动的 TypeScript/JavaScript 实现
实现思路
- 先统计所有活动的总需求人次,结合总人数计算出每人的基准参与次数,若总人次无法被人数整除,余数部分会分配给对应数量的人员多参与1次,保证所有人参与次数的差距最大不超过1次
- 维护每个人员的参与次数、已参与活动记录,分配单个活动名额时,优先选择当前参与次数最少、且未报名过本次活动的人员
- 按活动顺序逐批完成分配,所有活动都能保证招满所需人数
完整实现代码
// 人员类型定义 type Person = { name: string; // 已参与活动次数 participateCount: number; // 已参与的活动日期(避免同一个人重复参加同个活动) participatedActivities: Set<string>; } // 活动类型定义 type Activity = { date: string; required: number; // 已分配的人员名单 assigned: string[]; } /** * 人员分配核心方法 * @param personNames 所有参与人员的姓名列表 * @param activities 所有活动的基础信息(日期、所需人数) * @returns 完成分配的活动列表 */ function assignActivities(personNames: string[], activities: Omit<Activity, 'assigned'>[]): Activity[] { // 初始化人员基础数据 const persons: Person[] = personNames.map(name => ({ name, participateCount: 0, participatedActivities: new Set() })); // 逐个活动分配人员 return activities.map(activity => { const currentActivity: Activity = { ...activity, assigned: [] }; // 招满当前活动所需人数为止 while (currentActivity.assigned.length < activity.required) { // 筛选未参加过本次活动的人员,按已参与次数升序排序,优先选参与次数少的 const availablePersons = persons .filter(p => !p.participatedActivities.has(activity.date)) .sort((a, b) => a.participateCount - b.participateCount); // 取排序第一的人员分配到本次活动 const selected = availablePersons[0]; currentActivity.assigned.push(selected.name); selected.participateCount++; selected.participatedActivities.add(activity.date); } return currentActivity; }); } // ------------ 示例调用 ------------ const allPersons = ['John', 'Jack', 'Harry', 'Charlie', 'Jacob']; const allActivities = [ { date: '10.10.2021', required: 4 }, { date: '11.10.2021', required: 2 }, { date: '12.10.2021', required: 1 }, { date: '13.10.2021', required: 3 }, { date: '14.10.2021', required: 5 }, ]; const assignedResult = assignActivities(allPersons, allActivities); // 打印分配结果 console.log('活动分配结果:'); assignedResult.forEach(act => { console.log(`${act.date}:${act.assigned.join('、')}`); }); // 统计每人参与次数 const participateCountMap = assignedResult.reduce((map, act) => { act.assigned.forEach(name => map[name] = (map[name] || 0) + 1); return map; }, {} as Record<string, number>); console.log('每人参与次数:', participateCountMap);
如果要改为纯JavaScript实现,只需要删掉所有类型定义即可,逻辑完全通用。
运行示例输出
活动分配结果: 10.10.2021:John、Jack、Harry、Charlie 11.10.2021:Jacob、John 12.10.2021:Jack 13.10.2021:Harry、Charlie、Jacob 14.10.2021:John、Jack、Harry、Charlie、Jacob 每人参与次数: { John: 3, Jack: 3, Harry: 3, Charlie: 3, Jacob: 3 }
内容的提问来源于stack exchange,提问作者Matteo Lutz
相关产品推荐
相关产品推荐

