在Google表格中清除空行的脚本执行时间过长,导致超时。

huangapple go评论76阅读模式
英文:

Script for cleaning empty lines in a Google Sheet is taking too long and times out

问题

I am needing to run a simple script for Google Sheets to delete rows with empty cells. The spreadsheet I'm working on has 6000+ lines, and my script is taking so long that it times out (more than 6 minutes). Can someone help optimizing my script so that it would run faster? Thanks, Francisco.

I tried this code. It searches for empty cells through the sheet, column 2, and deletes the row when it finds it. But it is incredibly slow!!

英文:

I am needing to run a simple script for Google Sheets to delete rows with empty cells. The spreadsheet I`m working on has 6000+ lines, and my script is taking so long that it times out (more than 6 minutes). Can someone help optimizing my script so that it would run faster? Thanks, Francisco.

I tried this code. It searches for empty cells through the sheet, column 2, and deletes the row when finds it. But it is incredibly slow!!

function Macro3() {
    var spreadsheet = SpreadsheetApp.getActive();
    spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Database'), true);
    var sheet = spreadsheet.getActiveSheet();

    var i = 1
    while (i < (sheet.getMaxRows())){
        if (sheet.getRange(i,2).isBlank()){
            sheet.deleteRow(i)
        }
        else {
            i++
        }
    spreadsheet.getRange('A1').activate();
    }
};

答案1

得分: 0

你陷入了一个无限循环,并且还在使用错误的函数。

我看到你正在使用 getMaxRows()。这将计算工作表中的每一行,这将包括远比你实际需要的行数,因此会找到无休止的要删除的行数(因为工作表非常长,除了大约第6,000行以外几乎全部都是空白的)。

相反,请使用 getLastRow(),它将找到实际包含内容的最后一行。 (在这里阅读更多)

你可以通过倒数计数进一步简化你的分支逻辑。**而且你应该这样做!**因为,例如,如果你的原始工作表有6,000行,即使只删除了一行,你的代码版本也会陷入无限循环,因为第6,000行始终为空白(注意你的代码在删除空白行时没有增加,所以你将永远尝试计数到第6,000行)。

所以做一些像这样的事情:

function Macro3() {
    var spreadsheet = SpreadsheetApp.getActive();
    spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Database'), true);
    var sheet = spreadsheet.getActiveSheet();
    var i = sheet.getLastRow();

    while (i > 0){
        if (sheet.getRange(i, 2).isBlank()){
            sheet.deleteRow(i);
        }
        i--;
    }
};

最后,我不明白为什么你需要在每次迭代中执行 spreadsheet.getRange('A1').activate();。我建议你尝试删除它。

英文:

You're getting into an infinite loop, and you're also using the wrong function.

I see you are using getMaxRows(). That's going to count EVERY row in your worksheet, which will include far more rows than are actually relevant for your purposes, and therefore find an endless number of rows to delete (since the sheet is really long, and almost entirely blank beyond row ~6,000).

Instead, use getLastRow(), which will find the last row that actually has content. (read more here)

You can further simplify your branching logic by counting backwards. And you should! Because, for example, if your original sheet is 6,000 rows long, and even if only ONE row is deleted, your version of the code will be in an endless loop since the 6000th row is always blank (notice that your code doesn't increment when it deletes a blank row, so you'll iterate forever trying to count up to row 6000).

So do something like this:

function Macro3() {
    var spreadsheet = SpreadsheetApp.getActive();
    spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Database'), true);
    var sheet = spreadsheet.getActiveSheet();
    var i = sheet.getLastRow();

    while (i > 0){
        if (sheet.getRange(i, 2).isBlank()){
            sheet.deleteRow(i);
        }
        i--;
        spreadsheet.getRange('A1').activate();
    }
};

Finally, I don't understand why you'd need to do spreadsheet.getRange('A1').activate(); for every iteration. I suggest you try removing that.

答案2

得分: 0

我相信你的目标如下。

  • 你想要降低你的脚本的处理成本。

修改要点:

  • 当在循环中使用 getRangeisBlankdeleteRowactivate() 时,我担心处理成本会变得很高。这可能是你目前问题的原因。

在你的情况下,以下修改模式如何?

模式 1:

在这种模式下,通过过滤检索到的值来删除行。在这种情况下,当使用特定的文本样式和单元格格式时,这个脚本可能不太合适。

function Macro3() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Database");
  var range = sheet.getDataRange();
  var values = range.getValues().filter(([, b]) => b.toString());
  range.clearContent().offset(0, 0, values.length, values[0].length).setValues(values);
}

模式 2:

在这种模式下,使用 Sheets API 删除行。因此,请启用高级谷歌服务中的 Sheets API。在这种情况下,即使使用特定的文本样式和单元格格式,也可以使用此脚本,因为行将被删除。

function Macro3() {
  var sheetName = "Database";
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var ssId = ss.getId();
  var sheetId = ss.getSheetByName(sheetName).getSheetId();
  var { values } = Sheets.Spreadsheets.Values.get(ssId, `'${sheetName}'!B1:B`);
  var requests = values.reduce((r, [b], i) => {
    if (!b) {
      r.push({ deleteDimension: { range: { sheetId, startIndex: i, endIndex: i + 1, dimension: "ROWS" } } });
    }
    return r;
  }, []).reverse();
  if (requests.length == 0) return;
  Sheets.Spreadsheets.batchUpdate({ requests }, ssId);
}

参考:

英文:

I believe your goal is as follows.

  • You want to reduce the process cost of your script.

Modification points:

  • I'm worried that when getRange, isBlank, deleteRow, and activate() are used in the loop, the process cost becomes high. This might be the reason for your current issue.

In your situation, how about the following modification patterns?

Pattern 1:

In this pattern, the rows are deleted by filtering the retrieved values. In this case, when specific text styles and cell formats are used, this script might not be suitable.

function Macro3() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Database");
  var range = sheet.getDataRange();
  var values = range.getValues().filter(([, b]) => b.toString());
  range.clearContent().offset(0, 0, values.length, values[0].length).setValues(values);
}

Pattern 2:

In this pattern, the rows are deleted by Sheets API. So, please enable Sheets API at Advanced Google services. In this case, even when the specific text styles and cell format are used, this script can be used because the rows are deleted.

function Macro3() {
  var sheetName = "Database";
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var ssId = ss.getId();
  var sheetId = ss.getSheetByName(sheetName).getSheetId();
  var { values } = Sheets.Spreadsheets.Values.get(ssId, `'${sheetName}'!B1:B`);
  var requests = values.reduce((r, [b], i) => {
    if (!b) {
      r.push({ deleteDimension: { range: { sheetId, startIndex: i, endIndex: i + 1, dimension: "ROWS" } } });
    }
    return r;
  }, []).reverse();
  if (requests.length == 0) return;
  Sheets.Spreadsheets.batchUpdate({ requests }, ssId);
}

References:

huangapple
  • 本文由 发表于 2023年6月12日 12:18:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76453632.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定