Google provides an example of optimising a custom formula to recurse over an array where there is one. It helps with the whole efficiency thing The example provided from the Apps Script Page shows the an example where there is 1 parameter, as:
function DOUBLE(input) {
if (input.map) { // Test whether input is an array.
return input.map(DOUBLE); // Recurse over array if so.
} else {
return input * 2;
}
}
What if there are 2 or more parameters? How can we still recurse?
Thank you for your responses. The post to which TheMaster refers is probably right, but to be honest, I don't completely understand it. I have resolved my issue by referring back to Google's pages again. To add further to Ghost's question, I'd like to have one parameter as an array and other other a single constant - sorry for the confusion, I'll be sure to put more thoughts into my future questions.
My updated prototype formula looks like this:
function DOSOMETHING(x, y) {
return Array.isArray(x) ?
x.map(i => i.map(cell => cell * y)) :
x * y;
}
Happy to report it actually does what I want it to. x can be a single number or an array. y can only be a single integer in this case.
Since my original post, Google updated their pages to show the function using ternary operator, which made it easier for me to read & understand.
Related
I am currently working on external app using Google Sheets and JSON for data transmission via Fetch API. I decided to mock the scenario (for debugging matters) then simple JSON comes from my external app through prepared Code.gs to be posted on Google sheets. The code snippet I run through Apps-scripts looks like this:
function _doPost(/* e */) {
// const body = e.postData.contents;
const bodyJSON = JSON.parse("{\"coords\" : \"123,456,789,112,113,114,115,116\"}" /* instead of : body */);
const db = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
db.getRange("A1:A10").setValue(bodyJSON.coords).setNumberFormat("#"); // get range, set value, set text format
}
The problem is the result I get: 123,456,789,112,113,000,000,000 As you see, starting from 114 and the later it outputs me 000,... instead. I thought, okay I am gonna explicitly specify format to be returned (saved) as a text format. If the output within the range selected on Google Sheets UI : Format -> Number -> it shows me Text.
However, interesting magic happens, let's say if I would update the body of the JSON to be parsed something like that when the sequence of numbers composed of 2 digits instead of 3 (notice: those are actual part of string, not true numbers, separated by comma!) : "{\"coords\" : \"123,456,789,112,113,114,115,116,17,18\"}" it would not only show response result as expected but also brings back id est fixes the "corrupted" values hidden under the 000,... as so : "{"coords" : "123,456,789,112,113,114,115,116,17,18 "}".
Even Logger.log() returns me initial JSON input as expected. I really have no clue what is going on. I would really appreciate one's correspondence to help solving this issue. Thank you.
You can try directly assigning a JSON formatted string in your bodyJSON variable instead of parsing a set of string using JSON.parse.
Part of your code should look like this:
const bodyJSON = {
"coords" : "123,456,789,112,113,114,115,116"
}
I found simple workaround after all: just added the preceding pair of zeros 0,0,123,... at the very beginning of coords. This prevents so called culprit I defined in my issue. If anyone interested, the external app I am building currently, it's called Hotspot widget : play around with DOM, append a marker which coordinates (coords) being pushed through Apps-script and saved to Google Sheets. I am providing a link with instructions on how to set up one's own copy of the app. It's a decent start-off for learning Vanilla JavaScript basics including simple database approach on the fly. Thank you and good luck!
Hotspot widget on Github
In Google Sheets i have in a cell an array like [27, https://www.example.com/page1.html, false, false, 1]
How can i access its single parts with a formula?
I know a way through =SPLIT(), like =split(split(A2,"["),",") - but i would very like, if its possible, to access each part directly (each array has always the same amount of parts in my data set).
Maybe something like =QUERY(query(A2,",",1)) - cell, divider, item number...? - Result is 27.
=INDEX(SPLIT(A2,"[,]"),1)
SPLIT by each of these characters [,]
INDEX into the resulting array
I would like to take the chance and propose a solution using Google Apps Script. Basically, you can create your own custom function to accomplish this task.
Please follow these steps:
Go to Tools => Script editor from your spreadsheet file:
Clear the default Code.gs file, copy and paste this function and save the changes:
function indexArray(arr,pos) {
return array=arr.slice(1,-1).split(",")[pos-1]
}
You are now able to access the indexArray() function from within your spreadsheet file. It accepts two arguments, the desired cell that contains the array and the position of the element you would like to access, starting from 1:
=indexArray(A2,2)
For example, this will give you the second element of your array which is: https://www.example.com/page1.html.
Check these instructions out if you need more information how custom functions work. They are pretty straightforward.
In my Google Apps Script addon for Sheets, I have a custom function that will lookup prices. For example, a call like:
=LOOKUP_PRICE("apple")
would return the price for an apple. However, I've noticed that many users are not quoting the item name, instead just typing the following (which Sheets permits):
=LOOKUP_PRICE(apple)
When I try to retrieve the string value of the parameter with toString() all I get is the string "#NAME?".
Is there a way to handle this scenario and ideally retrieve the value of the parameter when not quoted?
Alternatively, is there a good way to detect this case and show the appropriate error message? All I've come up with so far is the following, but it feels dirty:
param.toString().toLowerCase() === "#name?"
Since these functions are written in JavaScript, as soon as you try to pass a string that isn't inside double quotes it will throw an error.
From the Custom Functions Documentation:
Google Sheets stores data in different formats depending on the nature of the data. When these values are used in custom functions, Apps Script treats them as the appropriate data type in JavaScript.
This means the functions use the normal JavaScript Data Structures i.e. string, number etc.
Your only real option here is to educate your users on how to use the function properly.
The easiest thing you could do to advise your users is give the function a JsDoc #customfunction tag, which allows you to customize the help text for the function itself. This helps your users with the syntax of your custom function.
Here's a brief example that you could modify to suit your requirement:
/**
* Searches for the price of the item specified.
*
* #param {"Apple"} item_to_find The item to find, e.g. "Apple", "Pear".
* #return Price of the item specified.
* #customfunction
*/
function LOOKUP_PRICE(item_to_find) {
if (item_to_find === "Apple") {
return "$4.99";
} else {
return "Not Found!";
}
}
When we start to call the custom function, we get this:
References:
Custom Functions in Google Sheets
JavaScript Data Structures
I am creating a google form where I have three sets of values and I want to randomly select one value from all the three sets and print them as a question.
The extension of the script is ".gs"
I tried using RANDBETWEEN(low, high) but the script throws an error. Seems like this is for google sheets.
Requesting for some help on how to create one.
For you random number, you'll need to use the Math library:
var nums = Math.floor(Math.random() * 4) + 1;
That should give you a random number between 1 and 5.
Seems like a little bit of confusion here:
RANDBETWEEN(low, high) is a special Google Spreadsheet function.
Inside a Google Script, you must use plain JavaScript (plus a few custom Google functions, like the FormApp.create() function you're using.)
In JavaScript, Math.random() is a way of getting a (pseudo) random number, but it returns a float between 0 and 1. To convert that into an integer in a range we have to use a bit of math. It might be helpful to define your own getRandomInt function, like this:
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
Then later on you could call getRandomInt(5), returning 0, 1, 2, 3, or 4.
Hi I am having an issue with deciding how to store/calculate a value. The value is this case is dynamically generated by executing a javascript function that is stored in a mysql database.
The company I work for originally did this because other values that are used by the stored javascript function can be changed and because this is done by a AJAX request, the value needs to be calculated on the clients side. Somehow this doesn't feel right, and I think there has to be a better way to store this.
Now I am not sure how I should solve this, but I hope some of you can point me in the right direction.
I hope I explained the problem clear enough.
EDIT: An example.
There is a value x that needs to be calculated and currently this happens.
function example(){
if(y == true){
return 0;
}
var result = z / areaM2;
if(result > 100){
return 1;
}
else{
return 2;
}
}
x = example();
y, z and areaM2 are actual stored variables.
You should only save the values that can change, not the function itself, even if it could change. In the latter case you'd need to provide multiple functions in a JavaScript file and have a property stored in your DB to define which function to use.