So, I’d like to read the value of J24, but J should be calculated. So I’m looking for a function that accept two parameters toe and column, instead of just writing J24.
GetFieldData(‘J’,24).
Although I'm not sure whether I could correctly understand about J should be calculated, if you want to use ‘J’,24 as J24 of the A1Notation, how about using INDIRECT as follows?
=GetFieldData(INDIRECT("J"&24))
Note:
Although I'm not sure about the script of GetFieldData, if you want to use the value from the cell J24 by giving J and 24 to the custom function, how about the following modification? In this case, value can be used by putting a formula of =GetFieldData("J",24) to a cell.
function GetFieldData(a, b) {
const value = SpreadsheetApp.getActiveSheet().getRange(a + b).getValue();
// do something.
}
Reference:
INDIRECT
Related
Here is my formula in G5
=ARRAYFORMULA(IF(AND(J5:J17=true,H5:H17=false),E5:E17*F5:F17*1.075,IF(AND(J5:J17=true,H5:H17=TRUE),0,IF(and(J5:J17=false,H5:H17=false),E5:E17*F5:F17,IF(and(J5:J17=false,H5:H17=true),0)))))
This works if Cols H,I, and J are all false, however once I start setting anything in H,I,or J to true, the formula stops working.
Thanks for any help, Im really stumped on this one.
I think you can simplify your formula all the way down to:
=arrayformula(E5:E17*F5:F17*not(H5:H17)*if(J5:J17,1.075,1))
A few pointers:
What you were trying to achieve boils down to: 'on each row, give me the value of the cell in colE * the value of the cell in colF, multiplied by 1.075 if the cell in colJ is ticked, unless the cell in colH is ticked, in which case give me 0.
You don't need to evaluate tickboxes against TRUE/FALSE as they contain a TRUE/FALSE themselves (so the =TRUEs & =FALSEs in your formula are redundant)
AND/OR in arrays don't work the way you might initially want them to as they are aggregating functions (i.e. they accept arrays as input by design) and wrapping them in ARRAYFORMULA to try to make them evaluate the input arrays row-by-row or column-by-column doesn't work. Historically the answer to this problem has been to use Boolean algebra (where AND is * & OR is +, FALSE=0 and TRUE<>0) as I've done here which normally makes for the most compact representation, but more recently it's also been possible to use MAP to process arrays element-by-element (in which case AND/OR can still be used) as per one of the other answers
You only really need to use IF statements if you want to return values other than TRUE/FALSE (1/0) as a result of a logical evaluation (like your colJ where you want TRUE=1.075 & FALSE=1); otherwise you can omit them and just use Booleans.
use:
=ARRAYFORMULA(IF((J5:J17=true)*(H5:H17=false), E5:E17*F5:F17*1.075,
IF((J5:J17=true)*(H5:H17=TRUE), 0,
IF((J5:J17=false)*(H5:H17=false), E5:E17*F5:F17,
IF((J5:J17=false)*(H5:H17=true), 0)))))
You can try to do this with MAP:
=MAP(J5:J17,H5:H17,E5:E17,F5:F17,LAMBDA(j,h,e,f,
IF(AND(j=true,h=false),e*f*1.075,IF(AND(j=true,h=TRUE),0,IF(and(j=false,h=false),e*f,IF(and(j=false,h=true),0))))))
I have little to no coding knowledge, so apologies if the solution is too obvious!
I am trying to add a Last Modified column to a Google Sheets file. To do this, I am using an AppScript function with the following code:
function setTimestamp(x) {
if(x != ""){
return new Date();
}
}
This works fine when I use setTimestamp(x) in my file. However, I am combining this with a Zapier action that creates a new row whenever new media is added. Every time a new row is created, any existing formulas are removed.
I assume I need to use ARRAYFORMULA to apply the setTimestamp formula to newly-created rows, but it must only apply to rows that aren't blank.
I have tried the following:
={"Last Modified";ARRAYFORMULA(setTimestamp(A2:A))} -> Only worked on first row
={"Last Modified";ARRAYFORMULA(B2:B=setTimestamp(A2:A))} -> Broke the file
={"Last Modified";ARRAYFORMULA(IF(A2:A)=1,setTimestamp(A2:A),"")} -> Expected 1 argument, got 3
Is there a way I can combine the IF into the script or a better way to solve the problem?
A public version of my file is available here: https://docs.google.com/spreadsheets/d/13zkVRPr2Wh5bHjCT8cenInHnBk7qkMkuEMdwUxC_cRU/edit?usp=sharing
All data is dummy data and stock photos.
Unfortunately, arrayformula does not function as an array map function for custom functions. (Even for native functions where you may expect it to work that way, it does not always, sadly.)
To handle array range, we need the custom function to handle array range directly. That also limits the number of individual calls to custom functions, which materially saves execution time.
To handle array range, there are 2 ways. I'll comment on both.
Array range directly as input of custom function
If the input is a single cell, it is read directly
If the input range spans more than a single cell, the data is read as nested lists: a list of lists of rows.
For example, A1 will be read as the data in A1. A1:B2 will be read as [[A1, B1], [A2, B2]].
You can remember it as columns of rows.
As for the input data format, numbers are taken without the display format. Texts are taken as strings.
If output is an array range, the result will automatically expend.
Thus, in your example, in B2 you can almost do
=setTimestamp(A2:A)
where setTimestamp() has been modified to
function out = setTimestamp(arr) {
out=Array(mat.length);
for (i=0;i<mat.length;i++){
j=0
if(arr[i][j] != ""){
out[i]=new Date();
}
}
return out
}
For more details, see the official help page. (Over the years, more details have become available.)
Almost, but not quite. For your direct question, above provides the answer. However, you seem to have an implicit requirement that your custom function is executed every time a new URL is found. Be careful that what happens here is that every time Google Sheet updates cell content, a new Date() is created and outputted.
Array range read within custom function
Since you know your URLs are in A2:A, and you want the output of your custom function to be B2:B, you can read and modify those ranges directly within your custom function via the Range Class.
In this route, you may find getLastRow(), getLastColumn() in Sheet and getNextDataCell() in Range convenient.
When you need to execute your custom function, you can run it manually or add onEdit() trigger to your custom function. (But onEdit() itself can mean substantial UI lag when using the sheet. It's usually more appropriate for sheets that parse external data automatically. See other triggers in the link for motions.)
In your example, you can almost do
function setTimestamp() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var lastRow = sheet.getLastRow();
var row=1;
var cell = sheet.getRange(row,1).getValue();
while (row<=lastRow) {
if(cell.getValue() != ""){
sheet.getRange(row,2).setValue(new Date());
}
cell = sheet.getRange(row,1,lastRow).getNextDataCell(SpreadsheetApp.Direction.DOWN);
row=cell.getRow();
}
}
which will scan for all URLs in A2:A and write current time to B2:B when executed.
Again, your example implicitly points to updating only when a new URL is found. So be careful about that. Use triggers as needed.
As for the need to place formula in B1, you can (and should) reference the output of your other application in a different sheet so that you or a different application of yours can edit without conflict.
Thus, for what was asked, we have everything.
Google Scripts use Javascript, and I haven't gotten around to learning Javascript yet, so I kept it really simple. Here is an example spreadsheet:
https://docs.google.com/spreadsheets/d/19yrUahvBt8GQMMZnykJ9i9xAoeVfMkw681HxOIj2_4I/edit?usp=sharing
The column on the left is a fixed list of terms. The column on the right is a list of manually entered terms by the user. If the user enters one of the terms on the left into one of the cells on the right, then the cell on the right should turn green (not case sensitive). So in this example, I want B4 and B5 to turn green.
Here is my script:
function Script1(singlecell, valuesy) {
for(var y = 0; y < valuesy.length; y++) {
var tempx = String(singlecell).toLowerCase().trim();
var tempy = String(valuesy[y]).toLowerCase().trim();
if((tempx === tempy)&&(!((tempx.length===0)||(tempy.length===0)))) {
return true;
}
}
return false;
}
Here are both my attempts to get some sort of conditional formatting using the script:
https://i.imgur.com/e6N8dWv.png
https://i.imgur.com/vvKB2L5.png
Neither of these work.
The reason I want this to work is because I'm using something similar in my budget spreadsheet.
I know there are more complicated methods where the script grabs the actual spreadsheet and changes the format of the cells itself. I would rather not use that method if I can help it.
EDIT: the "duplicate" question doesn't mention custom scripts at all. So while the solution may be the same (use "match" or "countif"), the question is not the same. Because the actual answer to my question is: "you can't use conditional formatting with custom scripts." (Also the first question was horrible and didn't include any code attempts or spreadsheets, so I'd rather mine not get deleted)
No need to create a custom function. You just need to use a different formula in your Conditional Formatting instead:
=ISNUMBER(MATCH(B1, $A$2:$A, 0))
I have a couple filtering formulas in Google sheet and would like edit them with another variable.
The filter is for example (it shows all non empty cells form a row):
=FILTER('Data Input'!$A$3:$A$9781; NOT(ISBLANK('Data Input'!$X$3:$X$9781)))
The X should be a variable that I can set from a different cell. I was trying stuff like INDEX
=FILTER('Data Input'!$A$3:$A$9781; NOT(ISBLANK('Data Input'!$INDEX(I13)$3:$INDEX(I13)$9781)))
but this just returns an error. Does anyone know how I can pass cell reference variables in a filter function?
It's hard to know for sure, but I believe you're looking for OFFSET rather than INDEX. OFFSET will allow you to enter integers in a cell which you would reference in your filter formula. Those integers would allow you to adjust which column you're using to check for NOT(ISBLANK...) which is what it looks like you're trying to do.
Maybe this will work, I13 will have the value of the column index (Column X = 24)
NOT(ISBLANK(OFFSET($A$1,2,$I$13-1):OFFSET($A$1,9780,$I$13-1))
OFFSET($A$1,2,$I$13-1):OFFSET($A$1,9780,$I$13-1) Should evaluate to $X$3:$X$9781 while I13 = 24
I'm using the command =COUNTA(I31:I) to count all non-empty cells in the column. The cells in the column contain this line of code:
=IF(ISNUMBER(D31), "X", "")
The result is that the cells are either an empty string (the line with add nothing "") or contain an X.
The problem now is that COUNTA counts all the cells after this procedure, empty or not. If I delete the long command line the cell is not counted and it works fine. So this long command line is adding something to the cell, so it appears not-empty even though it looks empty.
Any clues to what that is? My guess is that I should use some kind of Null operator instead of the "" to add nothing to the cell.
Note: For some reason, this seems to work in a previous version of Google Spreadsheet I had.
As a potential workaround, I could replace =COUNTA(I31:I) by checking specifically for x with =COUNTIF(I31:I;"X"). But I'm still curious as to the problem with COUNTA.
If it turns out that my cells are not empty 'enough' for this command, how can I then make them completely empty?
See Also: Count rows with not empty value
Unfortunately, this is functions as designed from Google.
Although I'm not sure why it's divergent from the way that Excel calculates COUNTA.
According to the Google Spreadsheet Documentation on COUNTA:
COUNTA counts all values in a dataset, including those which appear more than once and text values (including zero-length strings and whitespace).
Meaning that the only way to "make [the cells] completely empty" is to delete the entire contents, formula and all. But fear not...
Some workarounds:
Hypothetically, you should be able to do this with =COUNTIF(A3:A8,"<>"&""), but Google spreadsheets doesn't support the not equal to operator in the COUNTIF function according to these forums: 1, 2, 3
A workaround is to create a truthy or falsy array based on the condition and use SUMPRODUCT to count the truthy values like this:
=SUMPRODUCT((A3:A8<>"")*1)
Another option you could pursue would be to write a custom function and add it to Drive.
It's actually pretty easy to do so. Go to Tools > Script Editor and add the following script:
/**
* Works like COUNTA except does not include null strings
*
* #param {cellRange} myArray The value or range to consider when counting.
* #return Returns the a count of the number of values in a dataset.
* #customfunction
*/
function CountNotBlank(myArray) {
var output = 0;
for (i = 0; i < myArray.length; i++) {
if (myArray[i] != "") {
output += 1
}
}
return output;
}
Then use like this:
=CountNotBlank(I31:I)
I would try: =IF(ISNUMBER(D31), "X", iferror(1/0))
I am told that the iferror(1/0) returns nothing at all.