Reputation: 165
Based on some help I received yesterday, I've created a @customFunction
script to run in my spreadsheet which "appends" a value to a string.
In column A of the spreadsheet I have a student's current GPA (ex. 3.2) and in column B I have a string of their previously recorded GPAs (ex. [2,3,3,4.5,2.5,2.1,1.3,0.4]). The script adds the current GPA to the end of the string.
In this case current and stored are named ranges in the spreadsheet.
/** @customFunction */
function GPAweekly(current,stored) {
stored = stored.replace(']',','+current+']');
return stored;
}
This works fine when using a 1D range and for only a few rows. However when I use it for larger amounts of data, I hit the Google's service quota and get the “Service invoked too many times in a short time” error.
My next attempt was to use a 2D range and the map()
method to call my function recursively.
/** @customFunction */
function GPAweekly(current,stored) {
if (typeof current.map === "function" && typeof stored.map === "function") {
return current.map(GPAweekly);
return stored.map(GPAweekly);
}
stored = stored.replace(']',','+current+']');
return stored;
}
This seems to work until the script reaches the replace()
method and then I get an error in the spreadsheet cell stating "TypeError: Cannot find function replace in object 0".
I have two questions:
1) How can I get around this TypeError issue?
2) Is there a more elegant way of handling what I'm trying to achieve overall (keep in mind I'll have a couple thousand students data to deal with).
I apologize for the title. I couldn't quite figure out how to word it.
Upvotes: 2
Views: 788
Reputation: 9872
Note that Array#map
provides 3 parameters: the element, the index, and the original Array
. Thus when you call return current.map(GPAweekly);
, you are doing the equivalent of this code:
var results = [];
for (var i = 0; i < arr.length; ++i) {
results.push(GPAweekly(arr[i], i, arr));
return results;
In other words, because the 2nd parameter given to GPAweekly
is a number (0
), rather than the presumed string, you receive the given error message. Also note that a multiple-range input is passed as a 2D array, even for a single column, e.g.
=GPAweekly(A1:A5, B1:B5) ->
/**
current == [ [A1val], [A2val], [A3val], [A4val], [A5val] ]
stored == [ [B1val], [B2val], ... ]
*/
The solution is to ensure you call GPAweekly
with both of the original parameters, and to extract the value from the inner array:
function GPAweekly(current, stored) {
if (current.map && stored.map // Array test
&& current.length // Non-falsy length
&& current.length === stored.length // inputs are equally long
) {
return current.map(function (row, i) {
GPAweekly(row[0], stored[i][0]);
});
} else {
// at least one of the tested conditions failed, so handle appropriately...
...
}
}
Upvotes: 2