Generate random values and print them in Google Form - google-apps-script

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.

Related

Evaluate a string to a formula in Google Sheets

I am writing a math paper where i would like to display my calculations (formulas) separately from the solution.
I am currently working in Google Sheets.
The end goal would be to have one column with formulas and one column with answers.
I tried to work with GS to write a function that would take the string value from A1 and evaluate it in the B1 column.
I used this simple script that i found on:
https://support.google.com/docs/thread/13826624/evaluate-string-as-formula?hl=en
function run(input){
return eval(input);
}
It works with simple calculations like division, multiplication, addition and subtraction.
But the script doesn't solve basic exponents like 1 * 10^3 (it gives me 9). And square roots like sqrt(9) (gives me an #error)
I'm not sure which way to go from here.
The easiest solution would probably be to work the other way around: write your formulas normally, and use the formulatext() spreadsheet function to display the formula in an adjacent cell.

Weighted random in Google Sheets

I have three employees: John, Ashley and Mark. During the day we keep receiving jobs to do from our clients. I want that 20% of the jobs go to John, 50% for Ashley and 30% to Mark and for that I'm trying to build a Google Sheets that randomly select according to those weights (20%, 50% and 30%). You can see it in this google sheets file.
The way I found seemed good at first, the problem is that it uses RANDBETWEEN function, and it keeps randomizing everytime anything happens in the sheet, so it might look like this:
And if I simply add one row it changes completely:
Is there a way to fix the randomization (maybe copy-pasting values through script?) or an alternative way to do the same thing?
You can accomplish this via a custom function created in Google Apps Script, and use Math.random() to achieve the randomness. Unlike RANDBETWEEN, this won't refresh every time the sheet is edited, or even when the spreadsheet itself is refreshed. It also wouldn't require the data in A6:B16 (the people and percentages from A2:B4 would be enough).
To accomplish this, follow these steps:
In your spreadsheet, select Tools > Script editor to open a script bound to your file.
Copy this function in the script editor, and save the project:
function GET_RANDOM_PERSON(values) { // "A2:B4"
const random = Math.random(); // Random number between 0 and 1
const sheet = SpreadsheetApp.getActiveSheet();
// Change range if needed. Range could be a function argument if preferred:
if (!values) values = sheet.getRange("A2:B4").getValues();
let acc = 0;
values = values.map(value => {
acc = acc + value[1];
return [value[0], acc]; // Return accumulated probabilities
});
// Return person getting the job:
return values.find(value => value[1] > random)[0];
}
Now, if you go back to your spreadsheet, you can use this function as if you were using a regular sheets formula, as you can see here:
Reference:
Custom Functions in Google Sheets
With your current formula and setup, and without scripts, you can do it with iterative calculation:
Turn on Iterative Calculation: File > Spreadsheet Settings > Calculation
Make a tickbox. (I will use cell F2)
Change your formulas to look like this:
=IF($F$2;
vlookup(RANDBETWEEN(1;10);$A$6:$B$16;2;0);
E2)
If checked, the cells will calculate new randoms on change. If unchecked, it will prevent any changes until checked again. (Checked = unlocked).
When you first enter the formula, it will initialize to 0. Check the box to generate the first list.

Is it possible to determine if a number is recursive in Google Sheets?

So I'd like 1/3 (which equals 0.33333 recurring) to return true and 1/8 (which equals 0.125 non-recurring) to be false.
Something like =ISRECURRING(A1) which returns a boolean.
The reason for this is that I want to highlight cells that have had rounding applied to them.
You can build a JavaScript function to check that and use it in your sheet as an Apps Script custom function. To achieve this, follow these steps:
In your spreadsheet, select Tools > Script editor to open a script bound to your file.
Copy this function in the script editor, and save the project (credits to Larry Battle, whose answer here this function is based on):
function ISRECURRING(num) {
num = (num || "").toString().replace(/\d$/, '');
var RE_PatternInRepeatDec = /(?:[^\.]+\.\d*)(\d{2,})+(?:\1)$/;
return RE_PatternInRepeatDec.exec(num) ? true : false;
};
Now, if you go back to your spreadsheet, you can use this function as if you were using a regular sheets formula. You just have to provide the appropriate range as an argument, as you can see here:
Note:
As #Ron Rosenfeld noted in a comment below, this function will not work for very long repetends (e.g. 1/97). This is due to the precision limit that spreadsheets have (15 digits, as far as I know). Because of this, repetends longer than 7 digits won't be detected.
Reference:
Custom Functions in Google Sheets
Credit to #Ron Rosenfeld.
=A1-ROUND(A1,14) <> 0 works a treat. Where A1 is the number in question.
I can't guarantee that every rounded number works but it appears to work on all the examples I've tried.

Apps Script Custom Formulas Optimization

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.

Unquoted strings in function calls

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