I am working on a spreadsheet for a project that involves listing five ingredients for a recipe, along with a number value of how many of that ingredient is needed. I am then using functions in Google Sheets to automatically create a list of all unique ingredients and how many there are across all rows, broadly seen here:
enter image description here
For the "Ingredient List" I am using the code:
=SORT(UNIQUE(FILTER(FLATTEN(E4:E, G4:G, I4:I, K4:K, M4:M), FLATTEN(E4:E, G4:G, I4:I, K4:K, M4:M)<>"")))
And for the "#" column to the right of it I am using the code:
=IFERROR(SUM(FILTER($F$4:$F,O4=$E$4:$E)))+IFERROR(SUM(FILTER($H$4:$H,O4=$G$4:$G)))+IFERROR(SUM(FILTER($J$4:$J,O4=$I$4:$I)))+IFERROR(SUM(FILTER($L$4:$L,O4=$K$4:$K)))+IFERROR(SUM(FILTER($N$4:$N,O4=$M$4:$M)))
What I would like to do is to make so that if the value in column D ("Obtained?") is "Yes", then the entire row (E-N) is excluded from the two lists in columns O and P, but I do not want anything to be deleted. This would allow me to depopulate the "Ingredient List" as additional rows are marked "Yes", theoretically until a point where it is empty.
Is this something I can plausibly do using the tools within Google Sheets, and if so, how? Thank you!
I've tried some variations of "If" or "Ifs", but I need it to check every cell in one column from one cell (O4 and P4).
Can you try this in Cell O4. you may need to clear the exsiting formula(s) in columns O & P to let this formula freely expand.
=let(a,filter(E4:N,D4:D="No"),b,tocol(choosecols(a,1,3,5,7,9),1),c,tocol(choosecols(a,2,4,6,8,10),1),byrow(unique(b),lambda(z,{z,sum(filter(c,b=z))})))
I have more than 20k form responses (google sheet and google form) where some guys have selected the wrong data which is visible in my responses. How I know its wrong is because they needed to select the activity (an attribute) but they selected the similar activity name (let's call it X) which was for the previous year and this year's activity (let's call it Y) should have been the different one.
I know that after a certain date all the X activities are Y, so I need to modify the data while importing it from the responses.
I tried conditional formatting on the data but then the importrange doesn't work, it needs cells to be empty to work.
I learned about query statements but it doesn't allow UPDATE.
Please help me do this, I am okay if we need to use a macro. I'm looking for something like this (note that the following is the logic I'm looking for and not the actual code):
if date>"a date" and FC==X:
FC=Y
#FC being the column I wanna modify
Edit: I am unable to share the table as its confidential. Can tell you that first column is date/time of form and then there are 149 columns, one of them I need to modify based on the date. Let's Assume it has just 2 columns, A: date, B: activity (has 20 activities). So, if they have filled "X" activity after then change that activity to Y. I hope it helps in understanding.
Edit 2: Have put a dummy file as asked. So now the problem statement is after 21 May 2022 (inclusive) all "6" activity must be "2"
Try
function onOpen() {
SpreadsheetApp.getUi().createMenu('⇩ M E N U ⇩')
.addItem('👉 Update', 'myFunction')
.addToUi();
}
function myFunction() {
// parameters
var param = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Param')
var from = param.getRange('A2').getValue()
var before = param.getRange('B2').getValue()
var after = param.getRange('C2').getValue()
// data
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var range = sh.getDataRange()
var data = range.getValues()
data.filter(r => (r[0] >= from && r[1] == before)).forEach(r => r[1] = after)
range.setValues(data)
}
To avoid hardcoding and potential issue with dates, I put all parameters in a new tab called "Param" as follows
Good morning!
I've been searching high and low for how to do this, and while I feel like I get close I can't get anything more than 'invalid formula' from the conditional formatting in google sheets. So here's what I'm trying to do;
Column C on sheet 1 (Working List) needs to have a red background if the following conditions are met;
Column 'P' on sheet 2 (Complete) has the 'Address Changed' option in the drop down box (its the first one on the drop down, I've been struggling to figure out if it needs to be a '0' given its position in the list or if its 'Address Changed')
Column 'C' on sheet 2 has the same account numbers in Column 'C' on sheet 1.
I can set it up to find duplicate accounts, but I can't seem to figure out how to get the first rule for the drop down box to work. Advice?
Attempts thus far, none of them worked, all were tried separately and not in conjunction with each other. Google just says 'invalid formula' and won't save it or do anything with it.
=and(EQ(Complete!$O, "Address Changed"), EQ('Working List'!$C, Complete!$C))
=match($C2, indirect("Complete!$C:$C"), 0)
=if(EQ, indirect("Complete!$O, "Address Changed""), EQ('Working List'!$C, "Completed!$C"))
=and(indirect("Complete!$O:$O,$O="Address Changed""))
so I've tried to figure out a better way to get it working, and this is what I think might be closer to the answer.
=and(if($O:$O,indirect("Complete!$O:$O),0)),[match($C2,indirect("Complete!$C:$C"),0)]
***Friend helped me solve this. The following worked for what I needed....
=index(indirect("Sheet2!O:O"), match(C1, indirect("Sheet2!C:C"), 0)) = "Address Changed"
Take a look at this sheet with some foo data I built based on your sheet.
https://docs.google.com/spreadsheets/d/1RcM5WX3KWgWq-WWuPgyF-PZe3RP99qWF-IRpSr35Zik/edit?usp=sharing
I used some helper column, as you see.
if sheet2!P1 is changed to "Address Changed" K1 will have value of 1. This is a simple IF function.
if sheet2!C = sheet1!C, L will change to 1. This is another simple ARRAYFORMULA(IF())
Finally, column C will be formatted with the data from K1 and L by this formula
: =AND(L2=1, $K$2=1)
You can then hide the helper column / cell.
If you don't want to use helper column, look at the formula in column D :
=AND(INDIRECT("Sheet2!C2:C") = C2:C, INDIRECT("Sheet2!P1")="Address Changed")
This will serve your purpose.
You cannot refer to another sheet directly in conditional format formula, hence if you don't want to use helper column, you will have to use INDIRECT. This is also the reason why your formula failed in the first place.
I personally wouldn't recommend you to use INDIRECT though...
I have to make a conditional formating formula with cross-sheet references.
Basically I have many sheets, one with existing words, and another one with words we have to add. I want to highlight in "Feuille 6" the words that are already in "Existant". I tried many formulas, I read the doc, I still can't figure it out.
Quick edit : equiv = match, and ligne = row, it's just google sheet translating words into French..
Here's the formula I think I should use, but it's not working
=EQUIV(A,indirect("Sheet1!A"&LIGNE()))
Here's what the Feuille 6 looks like
Again, there should be highlighted words in Feuille 6, like " Action ", which already exists in the sheet " Existant ".
I tried replacing "Sheet1 "with "Existant" too.
Any tip please?
Thanks !
Try:
Assuming the sheet Existant has values in columns A to Z , and you are highlighting cells in column A
=countif(indirect("Existant!A:Z"), A1)
I use the following function
=DAYS360(A2, A35)
to calculate the difference between two dates in my column. However, the column is ever expanding and I currently have to manually change 'A35' as I update my spreadsheet.
Is there a way (in Google Sheets) to find the last non-empty cell in this column and then dynamically set that parameter in the above function?
There may be a more eloquent way, but this is the way I came up with:
The function to find the last populated cell in a column is:
=INDEX( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ; ROWS( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ) )
So if you combine it with your current function it would look like this:
=DAYS360(A2,INDEX( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ; ROWS( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ) ))
To find the last non-empty cell you can use INDEX and MATCH functions like this:
=DAYS360(A2; INDEX(A:A; MATCH(99^99;A:A; 1)))
I think this is a little bit faster and easier.
If A2:A contains dates contiguously then INDEX(A2:A,COUNT(A2:A)) will return the last date. The final formula is
=DAYS360(A2,INDEX(A2:A,COUNT(A2:A)))
Although the question is already answered, there is an eloquent way to do it.
Use just the column name to denote last non-empty row of that column.
For example:
If your data is in A1:A100 and you want to be able to add some more data to column A, say it can be A1:A105 or even A1:A1234 later, you can use this range:
A1:A
So to get last non-empty value in a range, we will use 2 functions:
COUNTA
INDEX
The answer is =INDEX(B3:B,COUNTA(B3:B)).
Here is the explanation:
COUNTA(range): Returns number of values in a range, we can use this to get the count of rows.
INDEX(range, row, col): Returns the content of a cell, specified by row and column offset. If the column is omitted then the whole row is returned.
Examples:
INDEX(A1:C5,1,1) = A1
INDEX(A1:C5,1) = A1,B1,C1 # Whole row since the column is not specified
INDEX(A1:C5,1,2) = B1
INDEX(A1:C5,1,3) = C1
INDEX(A1:C5,2,1) = A2
INDEX(A1:C5,2,2) = B2
INDEX(A1:C5,2,3) = C2
INDEX(A1:C5,3,1) = A3
INDEX(A1:C5,3,2) = B3
INDEX(A1:C5,3,3) = C3
For the picture above, our range will be B3:B. So we will count how many values are there in range B3:B by COUNTA(B3:B) first. In the left side, it will produce 8 since there are 8 values while it will produce 9 in the right side. We also know that the last value is in the 1st column of the range B3:B so the col parameter of INDEX must be 1 and the row parameter should be COUNTA(B3:B).
PS: please upvote #bloodymurderlive's answer since he wrote it first, I'm just explaining it here.
My favorite is:
=INDEX(A2:A,COUNTA(A2:A),1)
So, for the OP's need:
=DAYS360(A2,INDEX(A2:A,COUNTA(A2:A),1))
If the column expanded only by contiguously added dates
as in my case - I used just MAX function to get last date.
The final formula will be:
=DAYS360(A2; MAX(A2:A))
Here's another one:
=indirect("A"&max(arrayformula(if(A:A<>"",row(A:A),""))))
With the final equation being this:
=DAYS360(A2,indirect("A"&max(arrayformula(if(A:A<>"",row(A:A),"")))))
The other equations on here work, but I like this one because it makes getting the row number easy, which I find I need to do more often. Just the row number would be like this:
=max(arrayformula(if(A:A<>"",row(A:A),"")))
I originally tried to find just this to solve a spreadsheet issue, but couldn't find anything useful that just gave the row number of the last entry, so hopefully this is helpful for someone.
Also, this has the added advantage that it works for any type of data in any order, and you can have blank rows in between rows with content, and it doesn't count cells with formulas that evaluate to "". It can also handle repeated values. All in all it's very similar to the equation that uses max((G:G<>"")*row(G:G)) on here, but makes pulling out the row number a little easier if that's what you're after.
Alternatively, if you want to put a script on your sheet you can make it easy on yourself if you plan on doing this a lot. Here's that scirpt:
function lastRow(sheet,column) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
if (column == null) {
if (sheet != null) {
var sheet = ss.getSheetByName(sheet);
} else {
var sheet = ss.getActiveSheet();
}
return sheet.getLastRow();
} else {
var sheet = ss.getSheetByName(sheet);
var lastRow = sheet.getLastRow();
var array = sheet.getRange(column + 1 + ':' + column + lastRow).getValues();
for (i=0;i<array.length;i++) {
if (array[i] != '') {
var final = i + 1;
}
}
if (final != null) {
return final;
} else {
return 0;
}
}
}
Here you can just type in the following if you want the last row on the same of the sheet that you're currently editing:
=LASTROW()
or if you want the last row of a particular column from that sheet, or of a particular column from another sheet you can do the following:
=LASTROW("Sheet1","A")
And for the last row of a particular sheet in general:
=LASTROW("Sheet1")
Then to get the actual data you can either use indirect:
=INDIRECT("A"&LASTROW())
or you can modify the above script at the last two return lines (the last two since you would have to put both the sheet and the column to get the actual value from an actual column), and replace the variable with the following:
return sheet.getRange(column + final).getValue();
and
return sheet.getRange(column + lastRow).getValue();
One benefit of this script is that you can choose if you want to include equations that evaluate to "". If no arguments are added equations evaluating to "" will be counted, but if you specify a sheet and column they will now be counted. Also, there's a lot of flexibility if you're willing to use variations of the script.
Probably overkill, but all possible.
This works for me. Get last value of the column A in Google sheet:
=index(A:A,max(row(A:A)*(A:A<>"")))
(It also skips blank rows in between if any)
This seems like the simplest solution that I've found to retrieve the last value in an ever-expanding column:
=INDEX(A:A,COUNTA(A:A),1)
For strictly finding the last non-empty cell in a column, this should work...
=LOOKUP(2^99, A2:A)
What about this formula for getting the last value:
=index(G:G;max((G:G<>"")*row(G:G)))
And this would be a final formula for your original task:
=DAYS360(G10;index(G:G;max((G:G<>"")*row(G:G))))
Suppose that your initial date is in G10.
I went a different route. Since I know I'll be adding something into a row/column one by one, I find out the last row by first counting the fields that have data. I'll demonstrate this with a column:
=COUNT(A5:A34)
So, let's say that returned 21. A5 is 4 rows down, so I need to get the 21st position from the 4th row down. I can do this using inderect, like so:
=INDIRECT("A"&COUNT(A5:A34)+4)
It's finding the amount of rows with data, and returning me a number I'm using as an index modifier.
for a row:
=ARRAYFORMULA(INDIRECT("A"&MAX(IF(A:A<>"", ROW(A:A), ))))
for a column:
=ARRAYFORMULA(INDIRECT(ADDRESS(1, MAX(IF(1:1<>"", COLUMN(1:1), )), 4)))
This will give the contents of the last cell:
=indirect("A"&max(ARRAYFORMULA(row(a:a)*--(a:a<>""))))
This will give the address of the last cell:
="A"&max(ARRAYFORMULA(row(a:a)*--(a:a<>"")))
This will give the row of the last cell:
=max(ARRAYFORMULA(row(a:a)*--(a:a<>"")))
Maybe you'd prefer a script. This script is way shorter than the huge one posted above by someone else:
Go to script editor and save this script:
function getLastRow(range){
while(range.length>0 && range[range.length-1][0]=='') range.pop();
return range.length;
}
One this is done you just need to enter this in a cell:
=getLastRow(A:A)
Calculate the difference between latest date in column A with the date in cell A2.
=MAX(A2:A)-A2
To find last nonempty row number (allowing blanks between them) I used below to search column A.
=ArrayFormula(IFNA(match(2,1/(A:A<>""))))
The way an amateur does it is "=CONCATENATE("A",COUNTUNIQUE(A1:A9999))", where A1 is the first cell in the column, and A9999 is farther down that column than I ever expect to have any entries. This resultant A# can be used with the INDIRECT function as needed.
Ben Collins is a Google sheets guru, he has many tips on his site for free and also offers courses. He has a free article on dynamic range names and I have used this as the basis for many of my projects.
https://www.benlcollins.com/formula-examples/dynamic-named-ranges/
Disclaimer, I have nothing to gain by referring Ben's site.
Here is a screenshot of one of my projects using dynamic ranges:
Cell D3 has this formula which was shown above except this is as an array formula:
=ArrayFormula(MAX(IF(L2s!A2:A1009<>"",ROW(2:1011))))
Cell D4 has this formula:
="L2s!A2:E"&D3
This may work:
=DAYS360(A2,INDEX(A2:A,COUNTA(A2:A)))
To pick the last in a column of arbitrary, non-empty values ignoring the header cell (A1):
=INDEX(A2:A,COUNT(A2:A))
With the introduction of LAMBDA and REDUCE functions we can now compute the row number in a single pass through the cells (Several of the solutions above filter the range twice.) and without relying on magic text or numeric values.
=lambda(rng,
REDUCE(0, rng, lambda(maxrow, cell, if(isblank(cell),maxrow,row(cell)) ) )
)(A:A)
which can be nicely packaged into a Named Function for usage like
=LAST_ROWNUM(A:A)
It works on columns with interspersed blanks, and multi-column ranges (because REDUCE iterates over the range in row-first), and partial columns (like A20:A), still returning the actual row number (not the offset within the range).
This can then be combined with Index to return the value
=DAYS360(A2, Index(A1, LAST_ROWNUM(A:A)))
(In truth, though, I suspect that the OPs date values are monotonic (even if with blanks in between), and that he could get away with
=DAYS360(A2, MAX(A2:A))
This solution is identified above as relying on the dates being "contiguous" - whether that means "no blanks" or "no missing dates" I'm not certain - but either stipulation is not necessary.)