简体   繁体   English

复杂的转置超过了 Google Apps 脚本中的运行时间

[英]Complex transpose exceeding run time in Google Apps Script

I am receiving data in a single column and must transpose that into individual records.我在单列中接收数据,必须将其转换为单独的记录。 Some records will be 12 characters long, others 10, and the remainder 9. Furthermore, the latter 2 values in the 10 and 9-character-long records must be shifted 1 and 2 fields to the right, respectively.一些记录的长度为 12 个字符,其他的为 10 个,其余为 9 个。此外,10 个和 9 个字符长的记录中的后 2 个值必须分别向右移动 1 个和 2 个字段。 The first value in a given record is always a date.给定记录中的第一个值始终是日期。 I have created the following code which works well, except that it times out after about 6 minutes and 77 records.我创建了以下代码运行良好,除了它在大约 6 分钟和 77 条记录后超时。 I need to be able to handle 15 times as many if not more.我需要能够处理 15 倍甚至更多。

I embedded the calculation of the date objects in the else section of each if statement and nested the subsequent if statements in an effort to reduce unnecessary calculations.我在每个 if 语句的 else 部分嵌入了日期对象的计算,并嵌套了后续的 if 语句,以减少不必要的计算。 This got me from about 48 records to 77.这让我从大约 48 条记录增加到 77 条。

Very grateful for any clever insight 🙂非常感谢任何聪明的见解🙂


function transposeNew(){
  let ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  let lr = ss.getRange("A13").getDataRegion().getLastRow();
  let sr = 13

  // get the data column
  let data = ss.getRange(sr,1,lr-sr,1).getValues();

  // set up the rows loop
  let pasteRow = 2;
  let arrayField = 0;
  while (arrayField < data.length){
    //use the new Date() constructor to create a date object with the date value passed
    let isDate12 = new Date(data[arrayField+12]).getFullYear(); //processed; size input;record should include 12 rows & 13th should be a date to begin the next row
    if (isDate12 === 2020) {
      let record = data.slice(arrayField, arrayField+12);
      let recordTr = transposeSub(record);
      ss.getRange(pasteRow, 5, 1, 12).setValues(recordTr);
      arrayField = arrayField + 12;
    }
    else {
      let isDate10 = new Date(data[arrayField+10]).getFullYear(); //unprocessed;size input
      if (isDate10 === 2020) {
        let record = data.slice(arrayField, arrayField+10);
        let record1 = record.slice(0,8);
        let record1Tr = transposeSub(record1);
        let record2 = record.slice(8,10);
        let record2Tr = transposeSub(record2);
        ss.getRange(pasteRow, 5, 1, 8).setValues(record1Tr);
        ss.getRange(pasteRow, 14, 1, 2).setValues(record2Tr);
        arrayField = arrayField + 10;
      }
      else {
        let isDate9 = new Date(data[arrayField+9]).getFullYear(); //unprocessed;no size 
          input
        if (isDate9 === 2020) {
          let record = data.slice(arrayField, arrayField+10);
          let record1 = record.slice(0,7);
          let record1Tr = transposeSub(record1);
          let record2 = record.slice(7,9);
          let record2Tr = transposeSub(record2);
          ss.getRange(pasteRow, 5, 1, 7).setValues(record1Tr);
          ss.getRange(pasteRow, 14, 1, 2).setValues(record2Tr);
          arrayField = arrayField + 9;
        }
      }
    }
    pasteRow ++;
  }
}

function transposeSub(a)
{
  return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}

I see you create a loop and inside this while statement you call several times to SpreadsheetApp functions.我看到您创建了一个循环,并在此while语句中多次调用 SpreadsheetApp 函数。 This creates a connection to the spreadsheet, reads/changes its data and close connection a lot of times, that's why your code is taking too long to run.这会创建与电子表格的连接,读取/更改其数据并多次关闭连接,这就是您的代码运行时间过长的原因。 Please check GAS Best Practices batch operations section .请查看GAS 最佳实践批处理操作部分

You should consider banishing any get/setValue() inside while , instead, call getValues() to hold all values in a javascript array before while and then use setValues() after while to write all outputs at once.你应该考虑放逐任何get/setValue()while相反,调用getValues()之前保持在JavaScript数组的所有值while再使用setValues()while在一次写入所有输出。 The described concept is explored in this answer. 答案探讨了所描述的概念。

So it turns out that the problem was a flaw in the loop criteria;所以事实证明问题是循环标准中的一个缺陷; rookie mistake.菜鸟错误。 There was a data anomaly such that one record did not meet the criteria in any of the if statements and so the loop was continuing in perpetuity.存在数据异常,以至于一条记录不符合任何 if 语句中的标准,因此循环一直在继续。 I discovered this by inserting the values for pasteRow and arrayField next to each record on the sheet so that I could see where it was breaking.我通过在工作表上的每条记录旁边插入 pasteRow 和 arrayField 的值来发现这一点,以便我可以看到它在哪里中断。 Interestingly, the records stopped, but the pasteRow and arrayField values continued into the 20,000s before the app quit.有趣的是,记录停止了,但 pasteRow 和 arrayField 值在应用程序退出之前持续到了 20,000 秒。

I do note that the feedback provided by @Bruno Polo and @Cooper are correct.我确实注意到@Bruno Polo 和@Cooper 提供的反馈是正确的。 Shortly after posting this I reworked it to push the records into a new array and paste the array once complete.发布后不久,我对其进行了修改,将记录推送到一个新数组中,并在完成后粘贴该数组。 That failed due to the same reason noted above.由于上述相同的原因,这失败了。 I think I will go back to that version now that I understand the problem.我想现在我明白了这个问题,我会回到那个版本。

Thank you for looking at this with me.谢谢你和我一起看这个。 This is an extraordinary community of experts from whom I have learned so much!这是一个非凡的专家社区,我从中学到了很多! 😁 😁

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM