Javascript 如何有效地删除与其他工作表上的条件匹配的行?

Javascript 如何有效地删除与其他工作表上的条件匹配的行?,javascript,google-apps-script,google-sheets,Javascript,Google Apps Script,Google Sheets,我需要从大型(115244行)数据集中删除一个例外/排除列表。 被排除在外的总人数为1133人 我有以下代码: function removeExclusions() { const ss = SpreadsheetApp.getActive(); const exclusionSheet = ss.getSheetByName("Exclusion List"); const excludedAccounts = exclusionSheet .

我需要从大型(115244行)数据集中删除一个例外/排除列表。 被排除在外的总人数为1133人

我有以下代码:

function removeExclusions() {
  const ss = SpreadsheetApp.getActive(); 
  
  const exclusionSheet = ss.getSheetByName("Exclusion List");
  const excludedAccounts = exclusionSheet
    .getRange("C2:C" + exclusionSheet.getLastRow())
    .getValues()
    .reduce(
      (o, [c]) =>
        Object.assign(o, {
          [c]: true
        }),
      {}
    );
  Logger.log("Total accounts to remove: " + excludedAccounts); 
  
  const dataSheet = ss.getSheetByName("Data Sheet");
  const dataSheetMatches = dataSheet
    .getRange("A2:A" + dataSheet.getLastRow())
    .getValues()
    .reduce((ar, [a], i) => {
      if (excludedAccounts[a]) ar.push(i + 2);
      return ar;
    }, [])
    .reverse();
  Logger.log("Accounts left to remove: " + dataSheetMatches.length); 
  
  dataSheetMatches.forEach((r) => {
    dataSheet.deleteRow(r);
    Logger.log("Row:" + r + " has been deleted");
  });
}
然而,由于数据集的大小/帐户/行的数量,这需要运行-这需要一段时间,并达到谷歌在应用程序脚本运行时的超时

我需要一种更有效的方法来完成以下工作: 检查“排除列表”表(C列),然后删除“数据表”中与A列匹配的行

可以清除A-O行。列P-S标题行(1)包含一些我需要保留的公式

有什么建议吗

编辑 因此,我已将我的代码修改为以下内容:

function removeExclusions() {
  const ss = SpreadsheetApp.getActive();
  const exclusionSheet = ss.getSheetByName("Exclusion List");
  const exclusionRange = exclusionSheet.getRange("C2:C");
  const exclusionVals = exclusionRange.getDisplayValues();
  const dataSheet = ss.getSheetByName("Data Sheet");
  const dataSheetRange = dataSheet.getRange("A2:O");
  let dataSheetVals = dataSheetRange.getValues();
  dataSheetVals = dataSheetVals.filter((data) => {
    return !exclusionVals.includes(data[0]);
  });
  Logger.log(dataSheetVals);
}
但是,它仍然显示我希望它排除的行

它需要一个永恒的时间,并达到谷歌在应用程序上的超时时间 脚本运行时

原因是

dataSheet.deleteRow(r);
即使您在20行的工作表上尝试,速度也很慢,您几乎可以看到一行一行地被删除

除此之外,100K+行有时对于Google Sheets来说太多了,响应时间较慢

你可以使用的策略
  • 使用getValues()将“数据表”中的所有数据拉入变量。(如果可能,排除公式列)
  • 将“排除列表”列C拉入变量,就像您在代码中所做的一样
  • 使用“数据表”值数组上的.filter,通过删除不需要的行来创建新数组
  • 清除“数据表”值(如果可能,排除公式列)
  • 使用setValues()将精简后的数据写入“数据表”
  • 笔记
  • 这种方法也可能需要很长时间。它比deleteRow快得多,但是100K+行上的getValues和setValues以及15-20列可能需要一些时间。对执行时间的粗略估计是在“数据表”上进行手动选择所有/复制/粘贴测试,并查看您需要等待多长时间

  • 如果某个人/进程在运行函数的同时添加/删除/移动/编辑“数据表”,则可能会丢失数据。如果您可以通过使用一些隔夜一天一次的触发器来运行代码来防止这种情况,那么您应该很好

  • 通常,您的代码可能会中断,您可以在开始时复制工作表(用作备份),然后,如果所有操作都顺利执行,则在结束时删除重复的工作表

  • 一般来说,你应该考虑把你的数据从谷歌表移到可以处理大量记录的平台上,我使用BigQuice来解决这些问题。 编辑:对修改后代码的响应

    假设要比较的值是字符串:

    function somethingLikeThis() {
    
        const ss = SpreadsheetApp.getActive();
    
        // Load "Exclusion List" column C to array of strings
        const exclusionSheet = ss.getSheetByName("Exclusion List");
        const lastRowExclusionSheet = exclusionSheet.getLastRow();
        const exlusionList = exclusionSheet
            .getRange(2, 3, lastRowExclusionSheet - 2 + 1) // Data starts at row 2, column is C
            .getValues()
            .map(row => row[0].toString()) // Convert array of arrays to array of strings
            .filter(el => el.length > 0); // Remove empty rows if any
    
        // Read values from "Data Sheet"
        const dataSheet = ss.getSheetByName("Data Sheet");
        const lastRowDataSheet = dataSheet.getLastRow();
        const oldDataRange = dataSheet
            .getRange(2, 1, lastRowDataSheet - 2 + 1, 15) // Data starts at row 2, columns A-O
        const oldDataValues = oldDataRange.getValues();
    
        // Clear "Data Sheet"
        oldDataRange.clearContent();
    
        // Keep rows where column A value is not on the "Exclusion List"
        const newDataValues = oldDataValues
            .filter(row => exlusionList.indexOf(row[0].toString()) < 0);
    
        // Write reduced rows to "Data Sheet"
        if (newDataValues.length > 0) {
            dataSheet.getRange(2, 1, newDataValues.length, newDataValues[0].length)
                .setValues(newDataValues);
        }
    
    }
    
    函数类似于此(){
    const ss=SpreadsheetApp.getActive();
    //将“排除列表”列C加载到字符串数组
    const ExclutionSheet=ss.getSheetByName(“排除列表”);
    const lastrowExclutionSheet=ExclutionSheet.getLastRow();
    const exlusionList=排除表
    .getRange(2,3,LastRowExclutionSheet-2+1)//数据从第2行开始,列为C
    .getValues()
    .map(row=>row[0].toString())//将数组数组转换为字符串数组
    .filter(el=>el.length>0);//如果有空行,请删除空行
    //从“数据表”中读取值
    常量数据表=ss.getSheetByName(“数据表”);
    const lastRowDataSheet=dataSheet.getLastRow();
    const oldDataRange=数据表
    .getRange(2,1,lastRowDataSheet-2+1,15)//数据从第2行A-O列开始
    const oldDataValues=oldDataRange.getValues();
    //清除“数据表”
    oldDataRange.clearContent();
    //保留列A值不在“排除列表”中的行
    const newDataValues=oldDataValues
    .filter(行=>exlusionList.indexOf(行[0].toString())<0);
    //将减少的行写入“数据表”
    如果(newDataValues.length>0){
    dataSheet.getRange(2,1,newDataValues.length,newDataValues[0].length)
    .设置值(新数据值);
    }
    }
    

    代码没有经过测试,我没有实际的工作表。尝试使用getLastRow(),像“C2:C”这样的范围可以拾取工作表末尾的空行。

    .map()
    .filter
    都比
    .reduce()快。第一个
    .reduce()
    应该是一个
    .map()
    ,看起来
    .filter()
    更适合第二个
    .reduce()
    。范围如A2:lastRow()和maxxRows()之间的返回null,因此需要使用getRange(2,1.sheet.getLastRow()).getValues()进行过滤;相反,谢谢,伙计们。我已经采纳了一些建议,并决定使用一个过滤器,但是,它仍然没有返回我期望的结果。很抱歉延迟回复,测试和或多或少的工作正常。出于某种原因,它并没有删除一小部分结果——但大约有6个用户或其他什么。