我有数百个由模板工作表制成的电子表格。它们的工作表,行,列等都具有相同的编号/名称...
我已经向模板添加了一些数据验证。我想将数据验证从模板复制到每个电子表格。我有代码,它可以工作,但是会引发内存错误。
它总是引发错误-唯一改变的是在引发错误之前它已经处理了多少个目标电子表格。有时它会在抛出错误之前处理4个电子表格,有时是50个,有时更多/更少。我不知道为什么。
我将代码精简为工作示例。我不能共享源文件,但它们只是5张纸/标签和各种数据验证的普通电子表格。如果重要的话,数据验证将使用命名范围。例如:=REGEXMATCH(LOWER(google_drive_url) , "^https:\/\/drive\.google\.com\/drive\/folders\/[a-z0-9_-]{33}$")
。
我已经评论了下面的代码,但这里有一个回顾:
在我的真实代码中,我有一个目标文件ID数组。出于测试目的,我只使用一个目标文件,并多次应用模板中的数据验证。
function myFunction() {
var sourceFileID = "1rB7Z0C615Kn9ncLykVhVAcjmwkYb5GpYWpzcJRjfcD8";
var destinationFileID = "1SMrwTuknVa1Xky9NKgqwg16_JNSoHcFTZA6QxzDh7q4";
// get the source file
var sourceSpreadsheet = SpreadsheetApp.openById(sourceFileID);
var sourceDataValidationCache = {};
// go through each sheet and get a copy of the data validations
// cache them for quick access later
sourceSpreadsheet.getSheets().forEach(function(sourceSheet){
var sheetName = sourceSheet.getName();
// save all the data validations for this sheet
var thisSheetDataValidationCache = [];
// get the full sheet range
// start at first row, first column, and end at max rows and max columns
// get all the data validations in it
// go through each data validation row
sourceSheet.getRange(1, 1, sourceSheet.getMaxRows(), sourceSheet.getMaxColumns()).getDataValidations().forEach(function(row, rowIndex){
// go through each column
row.forEach(function(cell, columnIndex){
// we only need to save if there is a data validation
if(cell)
{
// save it
thisSheetDataValidationCache.push({
"row" : rowIndex + 1,
"column" : columnIndex + 1,
"dataValidation" : cell
});
}
});
});
// save to cache for this sheet
sourceDataValidationCache[sheetName] = thisSheetDataValidationCache;
});
// this is just an example
// so just update the data validations in the same destination numerous times to show the memory leak
for(var i = 0; i < 100; ++i)
{
// so we can see from the log how many were processed before it threw a memory error
Logger.log(i);
// get the destination
var destinationSpreadsheet = SpreadsheetApp.openById(destinationFileID);
// go through each sheet
destinationSpreadsheet.getSheets().forEach(function(destinationSheet){
var sheetName = destinationSheet.getName();
// get the full range and clear existing data validations
destinationSheet.getRange(1, 1, destinationSheet.getMaxRows(), destinationSheet.getMaxColumns()).clearDataValidations();
// go through the cached data validations for this sheet
sourceDataValidationCache[sheetName].forEach(function(dataValidationDetails){
// get the cell/column this data validation is for
// copy it, build it, and set it
destinationSheet.getRange(dataValidationDetails.row, dataValidationDetails.column).setDataValidation(dataValidationDetails.dataValidation.copy().build());
});
});
}
}
代码是否有问题?为什么会抛出内存不足错误?无论如何,有没有赶上/预防它?
为了更好地了解失败原因,我建议您对迭代进行计数,以了解正在经历的迭代次数。
我也刚刚注意到这条线
sourceSheet.getRange(1, 1, sourceSheet.getMaxRows(), sourceSheet.getMaxColumns()).getDataValidations().forEach(function(row, rowIndex){
这不是一个好主意,因为getMaxRows()
和getMaxColumns()
将获得工作表中的总行数,而不是包含数据的行数,这意味着,如果您的工作表是100x100且仅前20x20有数据单元格,您将获得覆盖整个10,000个单元格的范围,然后调用forEach
意味着您要遍历每个单元格。
一种更好的方法是使用getDataRange()
,它将返回一个覆盖整个数据(Documentation)的范围。这样一来,您可以使用更小的范围和更少的单元来处理。