下面的函数基于特定的列筛选器参数作为表行筛选器(隐藏行)。执行非常慢,尽管该表总共有115条记录。
有什么建议让它运行得更快吗?是否有任何后台功能我可以关闭,如在Excel(屏幕更新,表格计算)?
function filterOnDate(rowHeader, colFirst, colDate, typeFilter, valueFilter){
/* Hides rows of table where a date column meets a year or a month criteria. Params:
rowHeader: row number of table headers.
colFirst: column number of first table column.
colDate: column number of filter column (listing dates).
typeFilter: two possible types: "month", "year". Are we filtering on date's month or year.
valueFilter: filter value (i.e. month name or year number).
*/
if (valueFilter===undefined){ return; }
filterClearFilters(true); //Clear existing filters
var sh = SpreadsheetApp.getActiveSpreadsheet();
var ss = sh.getActiveSheet();
var tableData = ss.getRange(rowHeader+1, colFirst,ss.getDataRange().getLastRow()-rowHeader, ss.getDataRange().getLastColumn()-colFirst);
var numRows = tableData.getNumRows();
var values = tableData.getValues();
var months = ss.getRange("Months_Table").getValues();
if (typeFilter=="year") {
ss.getRange("Members_Filter_Month").clearContent();
} else {
ss.getRange("Members_Filter_Year").clearContent();
}
for (var i=0; i <=numRows-1 ; i++){
var row =values[i];
var myValue = row[colDate-colFirst]; //Date value of current row in loop, on filtered column
var bolHideRow = true;
if (!myValue=='') {
if (typeFilter="month" && months[myValue.getMonth()]==valueFilter){
bolHideRow = false;
}
if (typeFilter="year" && myValue.getFullYear()==valueFilter){
bolHideRow = false;
}
}
if (bolHideRow) {
ss.hideRows(i+rowHeader+1);
}
}
}
这是缓慢的,因为像在工作表上调用hideRows()这样的操作需要在底层调用API Service,每次可能需要几秒钟的时间。您无法做任何事情来加速API调用,最好的办法是尽可能避免以这种方式对它们执行许多操作。像你提到的Excel这样的显示问题在这里不是一个因素。
我看到一些选项。首先,您是否需要使用脚本来完成此操作?你可以用内置的表单过滤很容易地做到这一点。(见"数据"菜单下的"过滤器")
如果出于某种原因它绝对必须是一个脚本,那么您应该尝试尽可能地减少服务调用。
如果你隐藏的行比你显示的多,你可以翻转逻辑,在开始隐藏所有行,然后只显示你需要的行。
如果一系列的几行经常隐藏在一起,您可以跟踪要隐藏的连续行,然后将它们分组隐藏,而不是一次隐藏一个。
您可以将感兴趣的行写入单独的工作表,而不是隐藏行。使用像"setValues()"这样的单个函数一次写出许多值只是一个API服务调用,所以它花费的时间与在单行上调用hideRows()的时间相同。
当只有选定数量的列应用了过滤器时,我能够通过仅在应用了on的列上删除过滤器来提高性能。
sheet = SpreadsheetApp.getActiveSheet(); //for testing purpose only
var filter = sheet.getFilter();
if (filter !== null) { // tests if there is a filter applied
var range = filter.getRange(); // prevents exception in case the filter is not applied to all columns
var firstColumn = range.getColumn();
var lastColumn = range.getLastColumn();
for (var i = firstColumn; i < lastColumn; i++) {
if (filter.getColumnFilterCriteria(i) !== null) { // only remove filter on column if one exists.
filter.removeColumnFilterCriteria(i); // this is expensive (slow)
};
}