1

[背景故事] 我有一个 Google 表格,用于通过电子邮件将时间表发送给分包商。每个分包商都有自己的工作表,我还有最后一张名为 MasterSchedule 的工作表。

主计划使用对所有单个工作表的引用,以便所有分包商计划都是可见的。不过,这真的很长。因此,我在所有工作表中都包含了一个辅助列,它只返回,指示是否应在主控上显示一行。

然而,该行仍然显示在 master 上,但 helper 列恰好是 false。所以我使用了自动过滤器来隐藏它。

TLDR:

问题:Google Apps 脚本没有用于自动过滤的 API。就像使用标准等的 VBA。所以我看到的唯一选择是隐藏行。但这非常慢。我知道这个想法是减少对谷歌服务的调用次数,谷歌建议制作一个数组,然后在数组上执行一个调用。我不知道该怎么做。

我需要一个高效的脚本/函数来查看一列和每个读取为false的单元格,该函数将隐藏整行,并显示所有其他行。

最快的非脚本方法是使用 Google 表格版本的自动过滤器并简单地取消选中false

我尝试制作一个 for 循环来读取列中的每个单元格,如果单元格值为 false,则每次迭代都会隐藏该行。它非常慢。

看:

function MasterFilter() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();
  var maxRows = sheet.getMaxRows();

  //show all the rows
  sheet.showRows(1, maxRows);

  //get data from column B
  var data = sheet.getRange('B:B').getValues();

  //iterate over all rows
  for(var i=5; i< data.length; i++){
    if(sheet.getRange(i,2).getValue() == false){
      sheet.hideRow(i);
    }
  }
}
4

1 回答 1

2

我不得不更改您的原始代码的一行,以使其正常工作:

  sheet.hideRow(sheet.getRange(i,2));  // Operates on a range

有了这个,我在一个测试电子表格上计时,大约 200 行,true/false单元格均匀分布。执行记录报告[4.656 seconds total runtime]

正如您所怀疑的,您可以通过使用包含一组数据的数组(在本例中为所有 B 列)来减少服务调用。这是“隐藏”方法,使用数组来测试可见性:

function MasterFilter() {
  var headers = 4; // # rows to skip
  var sheet = SpreadsheetApp.getActiveSheet();
  var maxRows = sheet.getMaxRows();

  //show all the rows
  sheet.showRows(1, maxRows);

  //get data from column B
  var data = sheet.getRange('B:B').getValues();

  //iterate over all rows
  for(var i=headers; i< data.length; i++){
    if(data[i][0] == false){
      sheet.hideRow(sheet.getRange(i+1,1));
    }
  }
}

根据执行记录,这是[0.106 seconds total runtime]为了测试单。看着屏幕,它刷新的时候看起来像 3 或 4 秒。

这是另一种方法。在这一个中,我们读取了 Master Sheet 上的所有数据,然后使用Array.filter()将二维数组缩减为仅包含trueB 列中的行。在我们清除所有先前的内容后,将这个较小的集合写入 Master Sheet。[0.059 seconds total runtime]根据执行记录,这将执行时间减少了一半。再次,查看副本的刷新延迟使其看起来像几秒钟。

// Evaluation function for Array.filter()
function isVisible(row) {
  return (row[1] === true);  // Check column B
}

function MasterFilter2() {
  var headers = 4; // # rows to skip
  var sheet = SpreadsheetApp.getActiveSheet();
  var data = sheet.getDataRange().getValues();
  var headerData = data.splice(0,headers); // Skip header rows
  var filteredData = data.filter( isVisible );
  var outputData = headerData.concat(filteredData);  // Put headers back

  sheet.clearContents();  // Clear content, keep format

  // Save filtered values
  sheet.getRange(1, 1, outputData.length, outputData[0].length).setValues(outputData); 
}
于 2013-09-10T02:25:18.250 回答