按条件splice数组元素后如何恢复原数组?(月度排班场景)
解决方案:保留原数组的每日随机选取逻辑
你的核心问题是每次循环都直接修改了原数组dutyUserArray,导致后续天数的选取基于被修改后的数组,而非原始数组。最优的解决思路是:每天基于原数组创建一个临时过滤后的副本,完全不修改原数组,这样既满足当天的条件排除需求,又能保证次日使用原始数组。
优化后的代码实现
function generateRandomSchedule(month) { if(!month) { month = localStorage.getItem('currentDutyMonth'); } const monthNumber = moment().month(month).format('M'); const year = localStorage.getItem('currentYear'); const daysInMonth = moment(`${year}-${monthNumber}`, 'YYYY-MM').daysInMonth(); // 提前保存原始数组的拷贝,确保每次循环都基于原始数据 const originalDutyUsers = [...dutyUserArray]; for(let i=1; i<daysInMonth+1; i++) { let date = `${moment(i, 'D').format('DD')}.${monthNumber}.`; const keys = Object.keys(localStorage).filter(key => key.includes(date) && !key.startsWith(month)); // 收集当天需要排除的用户 const excludedUsers = []; keys.forEach((key) => { const keyValue = localStorage.getItem(key); // 合并Urlaub和Spaet的判断逻辑,减少重复代码 if((key.includes('Urlaub') || key.includes('Spaet')) && originalDutyUsers.includes(keyValue)) { excludedUsers.push(keyValue); } }); // 生成当天可用的用户列表(基于原始数组过滤) const availableUsers = originalDutyUsers.filter(user => !excludedUsers.includes(user)); // 从可用列表中随机选取 const randomName = availableUsers[Math.floor(Math.random() * availableUsers.length)]; const objectId = document.getElementById(`tdMa${date}`); objectId.value = randomName; localStorage.setItem(`${month}_tdMa${date}`, randomName); } }
关键修改说明
- 保存原始数组:用
const originalDutyUsers = [...dutyUserArray];创建原始数组的浅拷贝,确保后续所有循环都基于这份未修改的原始数据。 - 收集排除用户:不再直接修改原数组,而是先把当天需要排除的用户收集到
excludedUsers数组中,避免破坏原数组结构。 - 过滤生成可用列表:通过
filter方法从原始数组中排除掉当天不能选的用户,得到仅当天可用的临时数组,所有操作都不影响原数组。 - 简化重复逻辑:合并了
Urlaub和Spaet的判断条件,减少冗余代码,提升可读性。
备选方案:临时修改后恢复原数组(不推荐)
如果一定要通过修改原数组再恢复的方式实现,可以记录每次splice的元素和索引,在当天逻辑执行完后倒序恢复(因为splice会改变数组索引,倒序插入才能保证位置正确):
function generateRandomSchedule(month) { if(!month) { month = localStorage.getItem('currentDutyMonth'); } const monthNumber = moment().month(month).format('M'); const year = localStorage.getItem('currentYear'); const daysInMonth = moment(`${year}-${monthNumber}`, 'YYYY-MM').daysInMonth(); for(let i=1; i<daysInMonth+1; i++) { let date = `${moment(i, 'D').format('DD')}.${monthNumber}.`; const keys = Object.keys(localStorage).filter(key => key.includes(date) && !key.startsWith(month)); // 记录被移除的元素和索引 const removedItems = []; keys.forEach((key) => { const keyValue = localStorage.getItem(key); if(key.includes('Urlaub') && dutyUserArray.includes(keyValue)) { const index = dutyUserArray.indexOf(keyValue); if(index > -1) { removedItems.push({ index, value: dutyUserArray.splice(index, 1)[0] }); } } if(key.includes('Spaet') && dutyUserArray.includes(keyValue)) { const index = dutyUserArray.indexOf(keyValue); if (index > -1) { removedItems.push({ index, value: dutyUserArray.splice(index, 1)[0] }); } } }); const randomName = dutyUserArray[Math.floor(Math.random() * dutyUserArray.length)]; const objectId = document.getElementById(`tdMa${date}`); objectId.value = randomName; localStorage.setItem(`${month}_tdMa${date}`, randomName); // 倒序恢复原数组,避免索引混乱 removedItems.reverse().forEach(item => { dutyUserArray.splice(item.index, 0, item.value); }); } }
这种方案需要额外维护移除记录,逻辑更复杂,出错概率更高,因此优先推荐第一种基于数组过滤的方案。
内容的提问来源于stack exchange,提问作者Phil-Absynth
相关产品推荐
相关产品推荐

