强制 Google 电子表格公式重新计算
Force Google Spreadsheet formula to recalculate
我以前知道这个问题has been asked,但给出的答案对我的情况无效,因为它略有不同。
我创建了一个公式,用于查找 sheets 名称中的模式,然后使用它的内容生成输出。例如
function sampleFormula(searchTerm) {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheets = spreadsheet.getSheets()
.filter(function(sheet) {
// If sheet name starts with DATA_SHEET_...
return sheet.getSheetName().indexOf('DATA_SHEET_') === 0;
});
const result = [];
sheets.forEach(function(sheet) {
// We get all the rows in the sheet
const rows = sheet.getDataRange().getValues();
rows.forEach(function(row) => {
// If the row it's what we are looking for we pick the columns A and C
if (row[1] === searchTerm) {
result.push([ row[0], row[2] ])
}
});
});
// If we found values we return them, otherwise we return emptry string
return result.length ? result : '';
}
问题是,当 sheet 中名称以 DATA_SHEET_
开头的单元格发生变化时,我需要重新计算此公式。
我看到大多数答案(以及我通常做的)是传递我们想要观察的范围作为公式的参数,即使它没有被使用。但在这种情况下,它不会起作用,因为我们不知道我们正在观察多少个范围,我们甚至不知道整个 sheet 名称(它是由网络服务使用 Google Spreadsheet API).
我原以为 Google 脚本会有 range.watch(formula)
或 range.onChange(this)
之类的东西,但我找不到类似的东西。
我还尝试创建一个简单的函数来更改每个公式所依赖的单元格 B2
的值,但我需要立即恢复它,因此它不会被视为更改(如果我实际上更改了所有公式会中断):
// This does NOT work
function forceUpdate() {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheet = spreadsheet.getActiveSheet();
const range = sheet.getRange(1, 1);
const content = range.getValue();
range.setValue('POTATO');
range.setValue(content);
}
所以我不知道我还能做什么,我在多个 sheet 上有大约一百个公式,当我修改 DATA_SHEET_...
[=36] 时它们没有更新=]s.
要强制重新计算自定义函数,我们可以使用 "triggering argument" 唯一的任务就是触发自定义函数重新计算。这个触发参数可以是一个单元格引用,它将被一个简单的编辑触发器更新,或者我们可以使用一个编辑安装触发器来更新所有的公式。
使用单元格引用作为触发参数的示例
=sampleFormula("searchTerm",Triggers!A1)
使用编辑可安装触发器更新所有公式的示例
假设公式具有以下形式并且包含公式的单元格是 Test!A1 和 Test!F5
=sampleFormula("searchTerm",0)
其中 0 将被 sampleFormula
忽略,但会使其重新计算。
设置编辑可安装触发器以触发以下功能
function forceRecalculation(){
updateFormula(['Test!A1','Test!F5']);
}
进行更新的函数可能如下所示:
function updateFormula(references){
var rL = SpreadsheetApp.getActive().getRangeList(references);
rL.getRanges().forEach(function(r){
var formula = r.getFormula();
var x = formula.match(/,(\d+)\)/)[1];
var y = parseInt(x)+1;
var newFormula = formula.replace(x,y.toString());
r.setFormula(newFormula);
});
}
正如您想象的那样,上面的示例比使用单元格引用作为触发参数要慢,但在某些情况下可能很方便。
我以前知道这个问题has been asked,但给出的答案对我的情况无效,因为它略有不同。
我创建了一个公式,用于查找 sheets 名称中的模式,然后使用它的内容生成输出。例如
function sampleFormula(searchTerm) {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheets = spreadsheet.getSheets()
.filter(function(sheet) {
// If sheet name starts with DATA_SHEET_...
return sheet.getSheetName().indexOf('DATA_SHEET_') === 0;
});
const result = [];
sheets.forEach(function(sheet) {
// We get all the rows in the sheet
const rows = sheet.getDataRange().getValues();
rows.forEach(function(row) => {
// If the row it's what we are looking for we pick the columns A and C
if (row[1] === searchTerm) {
result.push([ row[0], row[2] ])
}
});
});
// If we found values we return them, otherwise we return emptry string
return result.length ? result : '';
}
问题是,当 sheet 中名称以 DATA_SHEET_
开头的单元格发生变化时,我需要重新计算此公式。
我看到大多数答案(以及我通常做的)是传递我们想要观察的范围作为公式的参数,即使它没有被使用。但在这种情况下,它不会起作用,因为我们不知道我们正在观察多少个范围,我们甚至不知道整个 sheet 名称(它是由网络服务使用 Google Spreadsheet API).
我原以为 Google 脚本会有 range.watch(formula)
或 range.onChange(this)
之类的东西,但我找不到类似的东西。
我还尝试创建一个简单的函数来更改每个公式所依赖的单元格 B2
的值,但我需要立即恢复它,因此它不会被视为更改(如果我实际上更改了所有公式会中断):
// This does NOT work
function forceUpdate() {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheet = spreadsheet.getActiveSheet();
const range = sheet.getRange(1, 1);
const content = range.getValue();
range.setValue('POTATO');
range.setValue(content);
}
所以我不知道我还能做什么,我在多个 sheet 上有大约一百个公式,当我修改 DATA_SHEET_...
[=36] 时它们没有更新=]s.
要强制重新计算自定义函数,我们可以使用 "triggering argument" 唯一的任务就是触发自定义函数重新计算。这个触发参数可以是一个单元格引用,它将被一个简单的编辑触发器更新,或者我们可以使用一个编辑安装触发器来更新所有的公式。
使用单元格引用作为触发参数的示例
=sampleFormula("searchTerm",Triggers!A1)
使用编辑可安装触发器更新所有公式的示例
假设公式具有以下形式并且包含公式的单元格是 Test!A1 和 Test!F5
=sampleFormula("searchTerm",0)
其中 0 将被 sampleFormula
忽略,但会使其重新计算。
设置编辑可安装触发器以触发以下功能
function forceRecalculation(){
updateFormula(['Test!A1','Test!F5']);
}
进行更新的函数可能如下所示:
function updateFormula(references){
var rL = SpreadsheetApp.getActive().getRangeList(references);
rL.getRanges().forEach(function(r){
var formula = r.getFormula();
var x = formula.match(/,(\d+)\)/)[1];
var y = parseInt(x)+1;
var newFormula = formula.replace(x,y.toString());
r.setFormula(newFormula);
});
}
正如您想象的那样,上面的示例比使用单元格引用作为触发参数要慢,但在某些情况下可能很方便。