Once again I'm back to SO for GAS problems because I'm not too familiar with Javascript/GAS yet. I'm having a bit of trouble with how slowly a script is running based on the method of handling function calls in an efficient manner.
I've read in several places (ah, it was here), that doing a "read-all" then "write-all" for getting-parsing-setting values (in Spreadsheets at least) is faster than doing a "get-one, write-one" method (for obvious reasons, this makes sense).
I know how to get all the values in a Range, but I'm not really sure how to go through the (multidimensional) array, process the data, and set a new Range accordingly.
The problem: The function takes about 2 seconds to start up, and takes about 5 seconds to run for 50 rows. The problem is, I will likely have thousands of rows in this Spreadsheet, and to have this function run to ensure that data is post-processed correctly so that Boomerang Calendar picks up the time data correctly is a tad ridiculous in my opinion. The script takes twice as long for every column of data needed to process, which is horrendous. I fear that during the next school semester I will often be going over my "GAS processing time limit."
Here is the starting code (bad, I admit):
function fixApostrophes() {
// Get the active spreadsheet to run the script on
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// Get the active sheet within the document to run the script on
var sheet = spreadsheet.getActiveSheet();
// Get max number of rows needed to process
var maxRows = sheet.getLastRow();
// Get the range for the startTime column and endTime column
var apostropheRange = sheet.getRange(1, 10, maxRows, 2);
// Get the value in each cell, remove apostrophes from the start,
// and replace the value in that cell
for (var i = 1; i < apostropheRange.getNumRows(); ++i) {
// Get the cells for startTime and endTime to speed things up a bit
var startCell = apostropheRange.getCell(i, 1);
var endCell = apostropheRange.getCell(i, 2);
// Get the values for startTime and endTime
var startTime = startCell.getValue();
var endTime = endCell.getValue();
// Remove apostrophes from start of startTime
while(startTime.charAt(0) == "'") {
startTime = startTime.substring(1);
}
// Remove apostrophes from start of startTime
while(endTime.charAt(0) == "'") {
endTime = endTime.substring(1);
}
// Set the values for startTime and endTime
startCell.setValue(startTime);
endCell.setValue(endTime);
}
}
This is highly related to my previous question about fixing a time-format apostrophe issue that was breaking Boomerang Calendar functionality for scheduling events.
The solution: Pull the values from a Range into a 2D array using the Range.getValues()
function. Process each value in the 2D array (row-by-row is probably the most logical method), then update the index of the edited value with the new value (see Srik-answer comments in code). After that, put the elements in the 2D array back into the original Range by using Range.setValues(2Darray)
. I hope this helps you if you came across it! This is also much faster than calling the API multiple times as seen in my original code.
function myNewLibraryFunction(startCol, numColumns) {
// Get the active spreadsheet to run the script on
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// Get the active sheet within the document to run the script on
var sheet = spreadsheet.getActiveSheet();
// Get max number of rows needed to process
var maxRows = sheet.getLastRow();
// Get the range for the startTime column and endTime column
var dataRange = sheet.getRange(1, startCol, maxRows, numColumns);
var values = dataRange.getValues();
// Get the value in each cell, remove apostrophes from the start,
// and replace the value in that cell
for (var i = 1; i < maxRows; ++i) {
// Get the values for startTime and endTime
var startTime = values[i][0];
var endTime = values[i][1];
// Remove apostrophes from start of startTime
while(startTime.charAt(0) == "'") {
startTime = startTime.substring(1);
}
// Remove apostrophes from start of startTime
while(endTime.charAt(0) == "'") {
endTime = endTime.substring(1);
}
values[i][0] = startTime; // New stuff from Srik's answer
values[i][1] = endTime; // New stuff from Srik's answer
}
dataRange.setValues(values);
SpreadsheetApp.flush(); // New stuff from Srik's answer
}
Basically, most of the function calls that you make to the APIs listed in GAS will require more time than regular JavaScript. In your case, reduce the number of calls to Range and Sheet classes
TIP: You can see how much time each call took in the Execution transcript