Google Apps脚本:如何检查数组任意位置的Unique ID以避免重复复制行
解决Unique ID遍历校验的问题
我完全理解你的困扰——原脚本的ID重复校验逻辑依赖两个工作表的行顺序一致,一旦「3 Months」表重新排序或者新增行不在末尾,校验就会失效。咱们来重构这部分逻辑,改成遍历整个已存在的Unique ID列表来判断是否重复,同时优化脚本的执行效率。
原代码的核心问题
原脚本里的ID校验部分有两个关键错误:
- 使用
j(当前匹配到的到期行计数)来索引CallOffIDs数组,这完全依赖行顺序一致,逻辑不成立 for (test in CallOffIDs)的遍历写法不符合需求,而且内部的break逻辑会导致只检查第一个元素就退出
修改后的完整代码
function contractSearch2() { // 获取工作表对象 const ss = SpreadsheetApp.getActiveSpreadsheet(); const dataSheet = ss.getSheetByName("Data"); const threeMonthsSheet = ss.getSheetByName("3 Months"); // 批量读取Data表的所有数据(避免循环内多次调用API) const dataLastRow = dataSheet.getLastRow(); const dataAllValues = dataSheet.getRange(1, 1, dataLastRow, 44).getValues(); // 提取Data表的到期日期列(第11列,索引从0开始是第10位) const endDates = dataAllValues.map(row => row[10]); // 计算三个月后的日期 const today = new Date(); const threeMonthsOut = new Date(today); threeMonthsOut.setMonth(today.getMonth() + 3); // 批量读取3 Months表的Unique ID列(第4列,索引3),并转换成Set用于快速查重 const threeMonthsLastRow = threeMonthsSheet.getLastRow(); let existingIds = new Set(); if (threeMonthsLastRow > 0) { const idValues = threeMonthsSheet.getRange(1, 4, threeMonthsLastRow).getValues(); // 将二维数组转成一维数组,再存入Set existingIds = new Set(idValues.flat()); } // 遍历Data表的每一行,筛选符合条件的行 const rowsToAdd = []; for (let i = 0; i < dataAllValues.length; i++) { const row = dataAllValues[i]; const endDate = new Date(endDates[i]); // 校验到期日期是否在三个月后的当月(保留原逻辑) if (endDate.getMonth() === threeMonthsOut.getMonth() && endDate.getFullYear() === threeMonthsOut.getFullYear()) { const uniqueId = row[3]; // Unique ID在第4列,索引3 // 检查ID是否已存在于3 Months表中 if (!existingIds.has(uniqueId)) { rowsToAdd.push(row); // 将新增的ID加入Set,避免同一轮遍历中重复添加 existingIds.add(uniqueId); } } } // 批量写入符合条件的行(比逐行写入高效很多) if (rowsToAdd.length > 0) { const nextEmptyRow = threeMonthsLastRow + 1; threeMonthsSheet.getRange(nextEmptyRow, 1, rowsToAdd.length, 44).setValues(rowsToAdd); } }
关键修改点说明
用Set存储已存在的Unique ID
- Set是一种无序的集合,
has()方法可以快速判断元素是否存在(时间复杂度O(1)),比遍历数组效率高得多,而且完全不依赖行顺序 - 先把「3 Months」表的所有ID提取出来转成Set,后续直接通过
!existingIds.has(uniqueId)判断是否重复
- Set是一种无序的集合,
批量读取/写入数据
- 原脚本在循环内多次调用
getRange()和getValues(),这会频繁触发Google Sheets API调用,导致脚本变慢 - 修改后一次性读取整个Data表和ID列的数据,最后批量写入符合条件的行,大幅提升执行效率
- 原脚本在循环内多次调用
修正日期判断逻辑(可选优化)
- 保留了你原有的“匹配三个月后的当月和当年”的逻辑,如果需要更精确的判断(比如到期日在今天到三个月后之间),可以把条件改成:
if (endDate >= today && endDate <= threeMonthsOut)
- 保留了你原有的“匹配三个月后的当月和当年”的逻辑,如果需要更精确的判断(比如到期日在今天到三个月后之间),可以把条件改成:
避免同一轮遍历重复添加
- 把新增的ID即时加入Set,防止Data表中同一ID出现多次时被重复添加到「3 Months」表
这样修改后,不管「3 Months」表的行怎么排序,都能准确校验Unique ID是否存在,而且脚本的执行效率也会提升不少,适合频繁运行的场景。
内容的提问来源于stack exchange,提问作者Dan Howard
相关产品推荐
相关产品推荐

