【问题标题】:Reduce script execution time - Google script减少脚本执行时间 - Google 脚本
【发布时间】:2021-12-02 02:29:01
【问题描述】:

我制作了一个可以正常运行的脚本(按照我的意愿运行),但是,它非常缓慢,按照这样的速度,大约需要 20 天才能完成。我等不及 20 天了,我还不够好,无法靠自己加快速度。

以下是任务的简要说明: Masterlist - 这是一张包含 23 列和 29000 多行的表格。 Seed - 这是我要将 Masterlist 复制到的空白工作表。 重复项 - 这是一张空白表,我将在其中存储任何重复的行。

流程: 从 Masterlist 中获取第一行。检查线是否已经在种子中。如果行不在种子中,则添加行。如果种子中已有行,则将行添加到重复项。无论哪种方式,从 Masterlist 中删除原始行。

重复的定义: 每行都有一个电子邮件列。列可以是单个电子邮件地址,也可以是由“;”分隔的多个电子邮件地址。如果在 Masterlist 的行中找到一封电子邮件,并且在 Seed 的行中已经存在,则这整行被认为是重复的。

示例:

“aaa@gmail.com”不是“a@gmail.com; aa@gmail.com”的副本

“bbb@gmail.com”是“b@gmail.com; bbb@gmail.com”的副本

此外,如果主列表中的电子邮件单元格为空,则不会被视为重复。

我的代码来了——它可以工作,但速度不够快。

function getSheet(name){
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(name);
  return sheet;
}

function getRowByID(sheet, rowID) {
  var range = sheet.getRange(rowID, 1, 1, 23);
  var value = range.getValues();
  return [range, value];
}

//main executes the entire thing
function main(){
  var sourceSheet = getSheet('Masterlist');
  var targetSheet = getSheet('Seed');
  var remainingSheet = getSheet('Duplicates');
  var counter = sourceSheet.getLastRow();
  var start = new Date();

  while(counter >= 2){
    var sourceLine = getRowByID(sourceSheet, 2)[1];
    var duplicates = checkEmailMatch(sourceLine, targetSheet);

    if(duplicates == 0){
      targetSheet.appendRow(sourceLine[0]);
      sourceSheet.deleteRow(2);
    }
    else{
      remainingSheet.appendRow(sourceLine[0]);
      sourceSheet.deleteRow(2);
    }
    counter--;
  }
}

//iterates through existing lines in the Seed sheet (locates the email cell and reads its contents)
function checkEmailMatch(row, seed){
  var sourceEmail = row[0][7];
  var counter = seed.getLastRow();
  var result = [];

  if(!counter){
    return 0;
  }
  else{
    var j = 0;
    var i = 2;
    for(i; i <= counter; i++){
      var seedLine = getRowByID(seed, i)[1];
      var seedEmail = seedLine[0][7];
      if(!seedEmail){}
      else if(compareEmails(seedEmail, sourceEmail) == true) {
        result[j] = i; 
        j++;
      }
  }
  return result;
}
}

//Compares each email in Masterlist ("; " separated) with each email in Source ("; " separated) 
function compareEmails(emailSeedCell, emailSourceCell){
  var seedEmails = emailSeedCell.split("; ");
  var sourceEmails = emailSourceCell.split("; ");
  for(var i = 0; i < seedEmails.length; i++){
    for(var j = 0; j < sourceEmails.length; j++){
      if(seedEmails[i] == sourceEmails[j]) return true;
    }
  }
  return false;
}

请帮助我 - 如果您需要任何其他信息,我很乐意提供!请注意,这是我的第三个脚本,欢迎提供任何反馈!

【问题讨论】:

  • 希望 SO 用户进行一些合理的研究。您是否已经阅读过官方文档中的“最佳实践”或尝试time 脚本的每个部分来找出耗时的部分?
  • 您犯了一个典型的错误,您在每次循环迭代时都使用getRow() 进行API 调用。您的数据量非常糟糕。通读best practices
  • 谢谢@TheMaster @Dmitry!我现在已经设法从几乎所有地方删除了 getRow() 。我目前正在努力弄清楚如何在添加该行时不调用它,但即使这样,它的工作速度也快了大约 100 倍!我认为这需要几个小时才能完成,这比我一开始的要好得多!太感谢了!请注意这是我的第三个脚本,如果您认为这个问题很愚蠢,我很抱歉。假设我正在学习如何做研究,希望下次我能做得更好!
  • 您问题中的代码是合理的。我记得我是这样写代码的。但是,如果您能够在二维数组中捕获所有数据并一次性对它们进行操作并使用 setValues() 保存最终结果,您会发现应用程序脚本相当快。请注意,一次删除一行很慢。
  • 如果你知道数组,那就是要走的路。在循环内重复调用.appendRow()deleteRow().getLastRow(),每个“非批处理”操作都会增加成本。在对数据的所有操作完成之前,请避免使用任何调用接触电子表格。

标签: google-apps-script google-sheets optimization mathematical-optimization


【解决方案1】:

感谢所有提供帮助的人,我设法想出了将执行时间减少超过 10000 倍的代码!谢谢大家 - 这是代码:

function sheetToArray(name){
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(name);
  var counter = sheet.getLastRow();
  var columns = sheet.getLastColumn();
  var array = sheet.getRange(2, 1, counter, columns).getValues();
  return array;
}

function compareEmails(emailSeedCell, emailSourceCell){
  var seedEmails = emailSeedCell.split("; ");
  var sourceEmails = emailSourceCell.split("; ");
  var result = false;
  for(var i = 0; i < seedEmails.length; i++){
    for(var j = 0; j < sourceEmails.length; j++){
      if(seedEmails[i] == sourceEmails[j]) result = true;
    }
  }
  return result;
}

function save2DArrayToSpreadsheet(name, array){
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(name);
  sheet.getRange(2, 1, array.length, array[0].length).setValues(array);
}

function main(){
  var masterArray = sheetToArray('Masterlist');
  var seedArray = [];
  var duplicateArray = [];

  for(var i = 0; i < masterArray.length; i++){
    Logger.log(i);
    if(!seedArray.length){
      seedArray.push(masterArray[i]);
    }
    else if(!masterArray[i][7]){
      seedArray.push(masterArray[i]);
    }
    else{
      var result = false;
      for(var j = 0; j < seedArray.length; j++){
        if(compareEmails(seedArray[j][7], masterArray[i][7]) == true){
          result = true;
        }
      }
      if(result == true){
          duplicateArray.push(masterArray[i]);
        }
        else{
          seedArray.push(masterArray[i]);
      }
    }
  }
  
  save2DArrayToSpreadsheet("Seed", seedArray);
  save2DArrayToSpreadsheet("Duplicates", duplicateArray);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-15
    • 1970-01-01
    • 1970-01-01
    • 2014-05-15
    • 1970-01-01
    相关资源
    最近更新 更多