I have defined a custom function like below. I want to use a named range in it but I keep getting the error that the named range is not defined. I tried to use INDIRECT function, but INDIRECT is also not recognized.
function RetentionCalculatorV1(x) {
return x* INDIRECT("V1.RetentionRateFrom1MonthAgo");
}
Spreadsheets functions are not available in Google Apps Script.
Try
return x* SpreadsheetApp.getActive().getRangeByName("V1.RetentionRateFrom1MonthAgo").getValue();
Related
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.
How do you count hyperlinked numbers within a simple Google Sheet formula? Currently the =SUM(F6:CS6) (for example) does not count cells with hyperlinks.
This requires a custom function, because built-in functions cannot detect what formulas are entered in other cells, they can only access values. The discussion at Google Product Forum confirms this. There is already a custom function posted there, but I wrote another one, a bit shorter and not case-sensitive:
function countLinks(rangeNotation, range) {
var formulas = SpreadsheetApp.getActiveSheet().getRange(rangeNotation).getFormulas();
return formulas.reduce(function(acc, row) {
return acc + row.reduce(function(acc, formula) {
return acc + (/^=HYPERLINK/i.test(formula) ? 1 : 0);
}, 0);
}, 0);
}
Usage example: =countlinks("A2:E10", A2:E10). Range notation has to be passed in as a string, because the function needs the range, not the values. But this also means it needs the second parameter to be recalculated in case something changes in the referenced range.
Warning: this only counts the hyperlinks created with hyperlink formula. It will not detect the links created by pasting rich text into a cell. Those links (which really should never be created) are not detectable with Google Apps Script at present.
If you dont want to use scripts and just want a formula, this might serve you: Countifs in Google Sheets with various 'different than' criteria in same row adds +1 value
Particularly, the answer about the function COUNTA might be what you are looking for.
Try to set the format of the column you want to sum to numbers.
I use the INIDRECT function in Google Spreadsheet to retrieve a defined cell range via the INDEX function. The formula in german declaration looks like this:
=IF(ISTZAHL($P2955),$P2955*IFERROR(INDEX(INDIRECT(CONCATENATE("projects_",$O2955,)),$B2955),1),"")
All worked fine since a year and now it doens't work anymore.
If I use the INDIRECT formula only it shows me the following error:
Parameter 1 of the function INDIRECT uses the value: "projects_GBP"
This is no valid range value.
If I specify the range value "projects_GBP" without INDIRECT function it will find the value.
Was there a change in the INDIRECT formula or why does my formula no longer work?
Out of nowhere it works again like a charm. Nothing has been changed.
Seems like it was/is an error from google.
in a google spreadsheet I want to use the formula SUMIF;
the syntax of function is SUMIF(A1:A10,"Paid",B1:B10)
as first parameter (and last) I want use a range of another google sheet;
I used the function IMPORTRANGE but the result is always #N/A
my code is:
sumif(importrange("xxhEwtMr2xxzRmiucxRgA5P119SEmsqL2R08gggt4Yyg", "list!$E:$E"),$S7,importrange("xxhEwtMr2xxzRmiucxRgA5P119SEmsqL2R08gggt4Yyg","list!$C:$C"))
where am I wrong?
ps.
the error pop-up report:
Error
Argument must be a range.
My understanding is that the third argument in the SUMIF must be a direct reference to the local worksheet.
You can either add an additional tab to import the data into, or try a different formula approach such as:
=SUM(QUERY(importrange("xxhEwtMr2xxzRmiucxRgA5P119SEmsqL2R08gggt4Yyg", "list!$C:$E"),"select Col1 where Col3 = '"&$S7&"'",0))
You could make an easier work around is to use the import range to a new sheet.
Then sumif it from that sheet. It will still dynamically update.
I'm trying yo create a formula in google spreadsheet that calculates the maximum value for all the cells above the current cell, in a way I can copy it to any cell and still workss. I tried using the ADDRESS function like this:
=MAX(ADDRESS(1;COLUMN()):ADDRESS(ROW()-1;COLUMN()))
But I get an parse error. I tried many variants of this code, but always get an error. Apparently, the ADDRESS function is not allowed as part of a range.
Is there any way to create a reference to a range based on the current cell position?
Was stuck on something very similar. Something like this should work.
=MAX(INDIRECT(1, COLUMN()) & ":" & ADDRESS(ROW()-1, COLUMN())))
This might be useful too if you want to get the sting address for a range:
=ADDRESS(row(A3:A6),COLUMN(A3:A6))&":"&ADDRESS(row(A3:A6)+rows(A3:A6)-1,COLUMN(A3:A6)+COLUMNS(A3:A6)-1)
This will return a string on the range, in this case
$A$3:$A$6
Using the INDIRECT function on your range string returns a range reference, which can then be used in a formula, eg.
INDIRECT(ADDRESS(1;COLUMN()):ADDRESS(ROW()-1;COLUMN()))
should work in
MAX(INDIRECT(ADDRESS(1;COLUMN()):ADDRESS(ROW()-1;COLUMN())))