Javascript 谷歌脚本说-超过了最大执行时间

Javascript 谷歌脚本说-超过了最大执行时间,javascript,google-apps-script,google-sheets,Javascript,Google Apps Script,Google Sheets,我正在使用下面的脚本从google电子表格中删除重复的行。脚本运行良好,但由于电子表格中的数据每天都在添加,现在脚本抛出“超出最大执行时间”错误。由于我对脚本编写还不熟悉,我不明白我的问题是什么 有人能帮我解决这个问题吗 function Deleteduplicates() { var SpreadSheetKey = "My key"; var sheetD = SpreadsheetApp.openById(SpreadSheetKey).getSheetByName("D

我正在使用下面的脚本从google电子表格中删除重复的行。脚本运行良好,但由于电子表格中的数据每天都在添加,现在脚本抛出“超出最大执行时间”错误。由于我对脚本编写还不熟悉,我不明白我的问题是什么

有人能帮我解决这个问题吗

    function Deleteduplicates() {
  var SpreadSheetKey = "My key";
  var sheetD = SpreadsheetApp.openById(SpreadSheetKey).getSheetByName("Daily");
  var sheetW = SpreadsheetApp.openById(SpreadSheetKey).getSheetByName("Weekly");
  var dataD = sheetD.getDataRange().getValues();
  var dataW = sheetW.getDataRange().getValues();
  //Daily
  var newDataD = new Array();
  for(i in dataD){
    var row = dataD[i];
    var duplicate = false;
    for(j in newDataD){
      if(row.join() == newDataD[j].join()){
        duplicate = true;
      }
    }
    if(!duplicate){
      newDataD.push(row);
    }
  }
  //weekly
  var newDataW = new Array();
  for(i in dataW){
    var row = dataW[i];
    var duplicate = false;
    for(j in newDataW){
      if(row.join() == newDataW[j].join()){
        duplicate = true;
      }
    }
    if(!duplicate){
      newDataW.push(row);
    }
  }
  sheetD.clearContents();
  sheetW.clearContents();
  sheetD.getRange(1, 1, newDataD.length, newDataD[0].length).setValues(newDataD);
  sheetW.getRange(1, 1, newDataW.length, newDataW[0].length).setValues(newDataW);
}

你的脚本没有问题。它刚好超过任何脚本允许的“最大执行时间”(当前为6分钟)

要解决此问题,您必须将问题分成“少于6分钟”的部分

例如,在代码中,您正在清除两张工作表中的重复项。尝试创建两个函数,每个函数一个,然后分别运行它们

此外,还可能有一些性能增强,可以使脚本在6分钟内运行。例如,我不确定加入每一行是否是进行数组比较的最佳方式(性能方面)

创建一个新的数组来重新设置数据也可能不是最优的,我可能会使用一个映射验证,这是一个常数时间,而不是您正在进行的O(n^2)双数组检查


一句话,这是一个限制,你必须生活在应用程序脚本。任何人提出的任何解决方案都只是一种变通方法,如果您的数据过大,最终也会失败。

从概念上讲,这应该要快一点。我还没有在大型数据集上尝试过。第一个版本将保留行的原始排序。第二个版本会更快,但会根据第一个文本中的列从第一个到最后一个对行进行排序

function Deleteduplicates() {
  var SpreadSheetKey = "My key";
  var ss = SpreadsheetApp.openById(SpreadSheetKey);
  var sheetD = ss.getSheetByName("Daily");
  var sheetW = ss.getSheetByName("Weekly");
  var sheets = [sheetD, sheetW];
  var toSs = {};
  for(s in sheets) {
    var data = sheets[s].getDataRange().getValues();
    for(i in data){
      // EDIT: remove commas from join("") for blank test
      data[i].unshift(data[i].join(""),(1000000 + i).toString());
      }
    data.sort();
    // remove blank rows -- Edit
    var blank = 0;
    while(data[blank][0].trim().length == 0) {blank++};
    if(blank > 0) data.splice(0, blank);
    // end Edit
    var len = data.length - 1;
    for(var x = len; x > 0; x-- ) {
      if(data[x][0] == data[x-1][0]) {
        data.splice(x, 1);
        };
      };
    for(i in data) {
      data[i].splice( 0, 1);
      };
    data.sort();
    for(i in data) {
      data[i].splice(0, 1);
      };
    toSs[sheets[s].getSheetName()] = data;
  };
  for(s in sheets) {
    var data = toSs[sheets[s].getSheetName()];
    sheets[s].clearContents();
    sheets[s].getRange(1, 1, data.length, data[0].length).setValues(data);
  }
}
更快地保留按join()排序的行以测试重复项

function Deleteduplicates() {
  var SpreadSheetKey = "My key";
  var ss = SpreadsheetApp.openById(SpreadSheetKey);
  var sheetD = ss.getSheetByName("Daily");
  var sheetW = ss.getSheetByName("Weekly");
  var sheets = [sheetD, sheetW];
  var toSs = {};
  for(s in sheets) {
    var data = sheets[s].getDataRange().getValues();
    for(i in data){
      // EDIT: remove commas from join("") for blank test
      data[i].unshift(data[i].join(""));
      }
    data.sort();
    // remove blank rows -- Edit
    var blank = 0;
    while(data[blank][0].trim().length == 0) {blank++};
    if(blank > 0) data.splice(0, blank);
    // end Edit
    var len = data.length - 1;
    for(var x = len; x > 0; x-- ) {
      if(data[x][0] == data[x-1][0]) {
        data.splice(x, 1);
        };
      };
    for(i in data) {
      data[i].splice( 0, 1);
      };
    toSs[sheets[s].getSheetName()] = data;
    };
  for(s in sheets) {
    var data = toSs[sheets[s].getSheetName()];
    sheets[s].clearContents();
    sheets[s].getRange(1, 1, data.length, data[0].length).setValues(data);
  }
}
根据亨里克的评论编辑


已编辑的5/8:删除空行(标记了2个已编辑区域)

从列表底部的“查看执行记录”菜单中,有一个给定的脚本运行时间。需要多长时间?执行失败:超过了最大执行时间[363.923秒总运行时间]也许像这样的帖子会有所帮助:O()和allto的答案很好。要挑剔,使用映射不是O(1)它的O(logn)每次查找我一直认为它是O(1),但我从未搜索过它。不管怎样,我现在做了,浏览器的实现是不变的。您测试过应用程序脚本实现吗?(谢谢你提出来)那些答案并不完全正确。是的,如果使用足够的内存(远远超过整个对象空间),但只能达到某一点,则可以得到O(1)。然后它必须进入log(n)。这里没有免费的午餐,只是log(n)需要一个非常大的n值才能注意到它不是一个常数。另一个更完整。查看logn的引入位置的一个简单方法是查看键本身。要比较键或生成散列,它与键字符串长度(基本上是logn)成比例。人们用来声明o(1)的技巧是说“很少冲突”,但这意味着一定的密钥长度,因此有logn。这里可以应用一个重要的应用程序脚本增强,即从循环中删除
setValues
,然后再执行(在单独的循环中)。因为如果您
setValues
然后调用`getValues^(在下一次迭代中),它将强制刷新电子表格并重新计算。因为第二次get中的值可能由于第一次set调用而更改。所以,一般提示,先把一切准备好,最后把一切安排好。不要打电话给set,让事情变得复杂。谢谢你,亨里克。收到你的来信总是一件令人愉快和启发的事。祝你有一个好剧本。谢谢你的剧本@ScampMichael,除了两件事之外,它很好用。正在创建表顶部的一个新空行,2。数据未按日期排序,日期是第一列,但按第二列(即名称)排序。谢谢你,Henrique,你的提示确实改变了执行时间,如果数据是按日期排序的,那么代码的第一个版本就应该如此。请参见代码中的2个编辑区域以解决空行问题。编辑的代码已解决了空行问题,但数据仍然未按日期排序@骗子迈克尔