使用JavaScript生成9组各含5场无重复赛事的比赛日方案求助
问题
我有一个包含45项赛事的数组,每项赛事包含主队(local)和客队(visitor)两支队伍。需要编写一个函数,生成9个比赛日,每个比赛日包含5场赛事,且所有赛事不可重复。
我尝试了以下代码:
const getRandomGame = (items, idsToAvoid) => { const game = getRandomFromArray(items); if (idsToAvoid.includes(game[0].id, game[1].id)) return getRandomGame(items, idsToAvoid); return game; }; const getRandomFromArray = (items) => { return items[Math.floor(Math.random() * items.length)]; }; // 这段代码在生成比赛日的函数内部 for (let i = 0; i < 9; i++) { counter++; let games = []; let avoidIds = []; for (let j = 0; j < 5; j++) { const game = getRandomGame(copyFinalGames, avoidIds); const localRng = Math.random() < 0.5; const local = localRng ? game[0] : game[1]; const visitor = localRng ? game[1] : game[0]; avoidIds.push(local.id, visitor.id); games.push({ id: counter, local, visitor, }); copyFinalGames = copyFinalGames.filter( (item) => !(item[0].id === game[0].id && item[1].id === game[1].id) ); } gamedays.push({ id: i + 1, games, }); }
但这个方案存在赛事重复的问题,而且用暴力方式规避重复,效率很低。请问有什么优化方案?
原数组示例如下:
[ [{ id: 1 }, { id: 2}], [{ id: 3 }, { id: 4}], [{ id: 5 }, { id: 6}] // 实际包含45组这样的赛事组合 ]
优化方案
核心思路
- 先洗牌再分组:用高效的Fisher-Yates洗牌算法打乱所有赛事,避免反复随机选取的低效操作
- 批量分割:将打乱后的赛事按每5个一组直接分割,正好得到9个比赛日,天然保证赛事不重复
- 随机主客场:对每个赛事单独随机分配主客场,保留原需求的随机性
优化后的代码
// Fisher-Yates洗牌算法,高效打乱数组 const shuffleArray = (array) => { const newArray = [...array]; for (let i = newArray.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [newArray[i], newArray[j]] = [newArray[j], newArray[i]]; } return newArray; }; const generateMatchdays = (allGames) => { // 1. 打乱所有赛事顺序 const shuffledGames = shuffleArray(allGames); const gamedays = []; let counter = 0; // 2. 每5个赛事为一个比赛日 for (let i = 0; i < shuffledGames.length; i += 5) { const dayGames = shuffledGames.slice(i, i + 5).map(game => { counter++; // 随机决定主客场 const isLocalFirst = Math.random() < 0.5; return { id: counter, local: isLocalFirst ? game[0] : game[1], visitor: isLocalFirst ? game[1] : game[0] }; }); gamedays.push({ id: gamedays.length + 1, games: dayGames }); } return gamedays; }; // 使用示例 // const allGames = [/* 你的45项赛事数组 */]; // const matchdays = generateMatchdays(allGames);
方案优势
- 彻底解决重复问题:所有赛事只被分配一次,不存在重复选取的可能
- 效率大幅提升:洗牌和分组的时间复杂度均为O(n),避免了原方案中递归重试和频繁过滤数组的低效操作
- 逻辑简洁易维护:去掉了复杂的
avoidIds校验和递归逻辑,代码可读性更高
内容的提问来源于stack exchange,提问作者nick
相关产品推荐
相关产品推荐

