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.
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
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.
From a previous question linked here ( Previous Question ) I learned about Sheets.SpreadSheets.get calling a JSON of sheet data that would allow me to get the backgroundcolors of a sheet within my project. Id previously been doing this with var BackgroundColors = ActiveWeekSheet.getDataRange().getBackgrounds(); but was told that the JSON method would be a faster read/write method. They directed me to do some reading on Javascript objects but after that I'm still confused.
I've got the following code. TestArray = Sheets.Spreadsheets.get("1irmcO8yMxYwkcLaxZd1cN8XsTIhpzI98If_Cxgp1vF8"); which seems to call a JSON with sheet specific data. A logger statement of TestArray returns this: testArrayObject: {"properties":{"gridProperties":{"rowCount":1000,"columnCount":26},"sheetType":"GRID","index":0,"sheetId":0,"title":"Awesome"}}
Community members previously suggested I could then find the background colors at: sheets[].data[].rowData[].values[].cellData.effectiveFormat.backgroundColor
I've highlighted one of the cells yellow but when reviewing the above JSON i can't seem to find anything that references color. There definitely isn't any multileveling of the JSON to refer to sheets->data->rowData->values->celldata.effectiveFormat.backgroundColor.
What am I missing here? Do I need to format things someway? Am I not calling the right JSON to start with?
Thanks!
As written in the documentation,
By default, data within grids will not be returned. You can include grid data one of two ways:
Specify a field mask listing your desired fields using the fields URL parameter in HTTP
Sheets.Spreadsheets.get(spreadsheetId, {
ranges:"Sheet1!A1:A5",
fields:"sheets(data(rowData(values(effectiveFormat.backgroundColor))))"
})
Set the includeGridData URL parameter to true. If a field mask is set, the includeGridData parameter is ignored
Sheets.Spreadsheets.get(spreadsheetId, {
ranges:"Sheet1!A1:A5",
includeGridData: true
})
Field mask documentation:
In a nutshell,
multiple different fields are comma separated, and
subfields are dot-separated.
For convenience, multiple subfields from the same type can be listed within parentheses.
You may test the API here
There are optional parameters in the spreadsheets.get method that will give you that data, but you need to explicitly include them:
ranges – The ranges to retrieve from the spreadsheet.
includeGridData – The cell data within specified range.
This specifies a range of just one cell (A1 in Sheet1), but you can specify a larger range and navigate through the array if you need to.
var TestArray = Sheets.Spreadsheets.get(SS_ID, {ranges: "Sheet1!A1", includeGridData: true});
Really important that you keep in mind this returns a Color object with RGBA
values that range from 0-1, but elsewhere apps script uses hex color or the conventional 0-255 RGB values.
Using a code.gs file, I have retrieved data from a Google Spreadsheet and put it into a 2-D array, and then manipulated the array a little bit (with things like transpose, condensing it, etc.).
I am trying to find out how to create a web app / web page that will display this 2-D array as an html table (subject to also being able to set table specifications, like width, color, etc.).
Does anyone have any ideas on how this can be done?
This will tell you how to do it, generally speaking. Just to display the HTML.
https://developers.google.com/apps-script/guides/html/
To choose specific data, you will want to use the .gs file to grab the spread sheet as you have already done. Now, when you're done modifying your array, store it in Properties Service, or Cache Service.
In your HTML page, write a JS function that calls back to the .gs file.
google.script.run
.withSuccessHandeler( function(array) { ... //We'll get to this in a moment... })
.getMyArray();
In your .gs file, write a function 'getMyArray'. Make it retrieve the array from Property or Cache Service and make it return the array.
Now, it the Success Handeler, use your array, and make it a table.
// 'array' here will be the return of .getMyArray()
.withSuccessHandler( function(array) {
for (var i in array) {
// Here, make every object into a string of the table you want
// i.e. "<table><td>" + array[i] + "<td> ..."
// Insert that string into some div.innerHTML
}
.getMyArray();
Easy as pi
Is there a way to access the cell coordinates (in A1 notation) of the cell that was passed in to my function?
For example, if my function is this
function displayA1Notation(myCell){
return myCell.getA1Notation();
}
and I put the following in cell B4:
=displayA1Notation(C6)
I'm hoping to see this:
C6
But what I actually see is this:
Kansas
("Kansas" is the actual cell value of C6)
I know this seems easy... I'm just stuck in trying to get it to work.
Thanks~!
Spreadsheet custom functions arguments contain only values pointed as arguments and not cell addresses. This fact not clear documented but there are a couple of similar questions here, for instance, this one. There is a workaround by using the build-in function ADDRESS. like in the following code
=myFunc(ADDRESS(ROW(F8), COLUMN(F8)))