Conditionally format first instance of value in column - google-sheets

I'm trying to style the first instance of a value in a column. I found this custom formula through googling:
=COUNTIF($A1:$A100,$A1)=1
but this styles the last instance of the value, and I'm not sure why.

try this formula:
=COUNTIF($A$1:$A1,$A1)=1

THE COUNTIF SOLUTION:
The formula =COUNTIF($A$1:$A1,$A1)=1 as suggested by Max is a common solution to this problem. It is a variation of the formula for finding duplicates : =COUNTIF($A:$A,$A1)>1.
COUNTIF DRAWBACK:
One of the drawbacks of using the COUNTIF formula is that it relies on the first parameter $A$1:$A1 in order to accurately evaluate the conidtional-formatting correctly. The formula works the same in the conditional formatting as it would if you were to physically put the formula in B1, and the copy it down the whole column. The first copy in B1 will appear as the original formula =COUNTIF($A$1:$A1,$A1)=1but the one in B2 will appear as =COUNTIF($A$1:$A2,$A2)=1.
This can be a real problem and result in false positives or maybe the conditional formatting not working at all if you are doing any sorting, cutting and pasting, dragging and dropping rows or cells, etc.
THE MATCH SOLUTION:
An improved version of this formula that eliminates the possibility of false positives and prevents the range from automatically being updated when it has been sorted, copied, cut, dragged, dropped, etc is as follows:
=MATCH($A1,INDIRECT("$A:$A"),0)=ROW()
EXPLANATION OF MATCH SOLUTION:
The only purpose in the INDIRECT formula is to prevent the range from automatically updating. If you would prefer it to update when you copy and paste you can instead do: =MATCH($A1,$A:$A,0)=ROW() The key to this formula working properly is that the MATCH formula parameter 2 looks at the entire column, that way when it finds the exact location of parameter 1 it can compare it to the row#. If there are duplicates within column A Match will only return the location of the first instance. Since parameter 2 is the entire column the answer it returns is also the row# of the first instance. So the second part of the formula above =ROW() will compare the first instance's row# to the row# of the current cell, if they are identical than the formula will entire formula will return TRUE
ADAPT MATCH SOLUTION TO FIND DUPLICATES (after first instance):
The MATCH formula can also be adapted to find all duplicates after the first entry. (basically the inverse) by changing the last part of the formula =ROW() into <ROW() So the duplicate finding formula would be: =MATCH($A1,INDIRECT("$A:$A"),0)<ROW()

Related

Output array formula, ignoring cells in output area that already contain data

I'm trying to work on a Google Sheet and make it as user friendly as possible, so when I'm not around others can't screw it up. I have previously copied the formula down the column, but I'm trying to do it in an array formula, that is in the header of the column so people don't need to copy the formula to other cells.
The formula is simply a VLOOKUP, comparing a cell to the left with the code, and retrieving the title and other information later. (I've had this working happily via copying the formula down the column.)
VLOOKUP($F$2:F, 'Lessons NEW'!$E$2:$F,2,false)
My problem comes when trying to do this using an array formula in the header. This also works properly, but doesn't allow me to do somethings needed.
={"Title";
ARRAYFORMULA(
IF($F2:$F<>"",
VLOOKUP($F$2:F, 'Lessons NEW'!$E$2:$F,2,false),
)
)}
Again this works happily.
HOWEVER. my issue is that on some rows I need to manually enter some info.
What I want to happen, is rows in the column that have data, in the array formula's destination to get skipped over and simply ignored during the array formula's output and end up containing what's been manually entered in them. (Some rows in the column will just be random manual entry stuff)
I've tried doing this via checking if there is a code in the cell to the left, and try to make it skip if so, or check if the destination cell has contents already and skip if so. but it seems that if I have anything in the output area of the array formula, it breaks it completely.
Does anyone have any suggestions of how I can accomplish this? Thanks!
Unfortunately there's no direct solution within ARRAYFORMULA. If you can, and ideally there are no in between rows added, you can add a column to the left to be hidden, and contain the formula adapted:
={"",VLOOKUP($F2, 'Lessons NEW'!$E$2:$F,2,false)}
Without ARRAYFORMULA it will be able to expand at any row that doesn't have a handwritten value. You may also protect that whole hidden column (that will mean also that no in between rows will be added by noon authorised people, may be also useful for you)
UPDATE
Sample script for copying the formula. Adapt the ranges and name of the sheet:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
SpreadsheetApp.getUi().createMenu("Custom")
.addItem("Copy Formula","copyformula")
.addToUi()
copyformula()
}
function copyformula(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sh = ss.getSheetByName("Sheet3")
var range = sh.getRange("D1")
range.copyTo(sh.getRange("D2:D"))
}
what you describe contradicts the intended usage of arrayformula. arrayformula is designed to roll out and for that, it needs an empty space. any manual input in that empty space will render the arrayformula out of the game. there are only two solutions for your issue:
not use arrayformula but VLOOKUP formula in every cell
use a script that will inject the formula only if there is no manual input
and one more hybrid solution - have your arrayformula in one column and your manual input in the next column, and then have 3rd column that will gather the data like if manual column is empty output vlookup otherwise output manual input

Unique Filter multiple sheets with ArrayFormula

I have no idea how to title this post, apologize in advance.
I have several sheets with a number in Column I and a name centered and merged in columns A:H. I want to obtain the name from A:H of the corresponding value within I but do have duplicates, therefore I need the nth value when permitted. The formula I have so far works up to the point it does not autofill down as an ArrayFormula, so when I drag the formula down I get an #REF! error due to the fact that when a duplicate is found it cannot overwrite the formula below.
This will be easier to showcase: LINK TO SHEET.
Essentially, in the main sheet all the values in I:I of all the other sheets are obtained and sorted, then using that column I want to return the name that corresponds to the value, allowing for duplicates to work themselves out. I believe my issues resides in the $B1 part at the end of the formula preventing it from being an array.
=ARRAYFORMULA(UNIQUE(FILTER({Sheet2!$A$1:$A;Sheet3!$A$1:$A;Sheet4!$A$1:$A},{Sheet2!$I$1:$I;Sheet3!$I$1:$I;Sheet4!$I$1:$I}=$B1)))
Cell F2 on the Sheet1 tab:
=QUERY({Sheet2!A:I;Sheet3!A:I;Sheet4!A:I},"select Col1,Col9 where Col9>0 order by Col9 asc",0)
You can read more about query here.

How to get only one of two repeating values

The Issue
In simple terms, I am trying to set a formula for an alternating pattern. The issue I keep running into is the fact that there are two alternating values, and Google Sheets doesn't like to repeat only one of those values without the other.
I have created an example sheet to demonstrate my issue. In Column A, a date is input. Column B and Column C then autofill with the day of the week and AM or PM respectively. Every other value in Column C alternates between AM and PM. I am trying to set it up so that the row is blank until a value in input in Column A. The issue comes when there is an odd number of Dates in Column A. Note that the alternating AM/PM pattern will never change.
What I've Tried
As seen in the image above, there are three main methods that I have tried. The data in C2:C8 is the desired result.
Method 1:
E2: =transpose(split({rept(join(";",{"AM";" "})&";",(roundup(counta(A2:A9)/2)))},";"))
F3: =transpose(split({rept(join(";",{"PM";" "})&";",(counta(A2:A9)/2))},";"))
These formulas work separately, and best represent what I am trying to accomplish, but I have not found a way to combine them to work together in one column.
Method 2:
H2: =transpose(split({rept(join(";",{"AM";"PM"})&";",(roundup(counta(A2:A9)/2)))},";"))
This is essentially the same as Method 1, but put into one formula. The issue here is that Google Sheets doesn't like to repeat half a number of times. So if the number of times to repeat (counta(A2:A9)/2) contains a half (i.e. 3.5), it will still round down to the nearest whole number.
Method 3:
J2: =ArrayFormula(TEXT(SEQUENCE(3),"")&{"AM";"PM"})
This one appeared most promising to me because when incrementing by one, it added one row, but I quickly ran into the issue where if I went over a sequence number of 2, it threw the error Array arguments to CONCAT are of different size.
References
I have used various search terms and websites to try to solve this, and have yet to find something that works. I may be missing something very simple, though, and hopefully this is a quick solution.
Example Sheet:
https://docs.google.com/spreadsheets/d/1I3EtptFLfDHpAQ8AR6Lwa01dSpJ3Cy8MTX1_OjHExSc/edit?usp=sharing
All my formulas are derived from the websites below:
REPT Function in Google Sheets
How to Repeat Multiple Columns N Times in Google Sheets
Delete everything in Col C (including the header) and place this formula in C1:
=ArrayFormula({"AM/PM"; IF(A2:A="",,IF(COUNTIFS(A2:A,A2:A,ROW(A2:A),"<="&ROW(A2:A))=1,"AM","PM"))})
The COUNTIFS finds the number of matches for the date "up to this row" for every row. Since that count will (or should) only ever be a 1 or a 2, the IF makes easy work of assigning "AM" or "PM" accordingly.
If I understand correctly it is enough to use ISEVEN function to alternate by rows:
=ArrayFormula(IF(A2:A,CHOOSE(ISEVEN(ROW(A2:A))+1,"PM","AM"),))

COUNTIF Formula moves down when row at top added

I have the following COUNTIF Formula in my Google Sheet.
=COUNTIFS('Events/Incidents'!$E$3:$E,X4,'Events/Incidents'!$I$3:$I,"Accident")
This is a sample of the sheet which has the formula in the first row under the "Accidents" header:
It works until a user adds a row 3 to the top of the source sheet (Events/Incidents) then the formula changes to the following so that it captures row 4 down instead of the desired row 3.
=COUNTIFS('Events/Incidents'!$E$4:$E,X4,'Events/Incidents'!$I$4:$I,"Accident")
I used the Query function for "All Events" (the first 3 columns). The Countif formula is under each of the Incidents. In my Countif example, X4 is the Employee, John White which was returned in the QUERY.
The QUERY continues to return/include row 3 but I don't know how to do this for the individual Incidents. I tried adding ArrayFormula to the Countif function but I have the same problem.
Would appreciate some help with this.
I understand that you want to update your QUERY to reflect the correct row without resorting to returning the Branch in every response. If my comprehension is correct, there is a way to reach your goals with little modification.
First, you'll have to create a named range that includes the whole table (from the headers to the last row). You can then use this named range in every formula so new rows can be detected without changing the formula per se.
Finally, you can modify your QUERY to return only the values of Incidents in a Branch with something similar to =QUERY(myNamedRange,"SELECT G WHERE A = 'Auckland'"). That QUERY won't return the Branch, only the Incidents. If you keep having any doubts, please ask me for further help.
I worked it out by combining Countifs with ImportRange:
=COUNTIFS(IMPORTRANGE("1-f6OU8ylDSlpqdpt4P5B7GDcIel3IboVkUbY2huMA6U","Events/Incidents!$E$3:$E"),X4,IMPORTRANGE("1-f6OU8ylDSlpqdpt4P5B7GDcIel3IboVkUbY2huMA6U","Events/Incidents!$I$3:$I"),"Accident")

Return column header for last date in Google Sheets as an array formula

I've got a number of columns used to track some stages of Google Sheets entries with dates. I'd like a column that returns the latest stage for each entry, preferably using an array formula since this is a list that will be constantly added-to and copying the formulae down to new rows is a pain (this is something that will end up in with an end-user so needs to be straightforward).
This is a sample of my desired input/output.
I tried using array formulae combined with this lookup trick, but I think changing the inputs of that formula to multi-row ranges means the result ignores what row the entry is on. For instance wrapping the lookup in ARRAYFORMULA and applying it to the sample returns "Stage4" on every line. Alternatively I think there might be a way to do this using QUERY/FILTER but I'm getting nowhere. Thanks everyone.
EDIT: For clarification, the 'Stages' are not going to be numbered, but will be text fields (potentially dynamic ones, hence my reticence to use an HLOOKUP).
Assuming "Stage1" is in cell A2 and that you can not jump stages. You can use this formula on F3 to auto-populate your output:
=ArrayFormula(transpose(
split(
concatenate(
if((A3:D<>"")*(B3:E=""),A2:D2,"")&
if(column(A2:D2)=column(D2),char(9),"")
)
,char(9),true,false
)
))
You can see that we're determining the stage by checking the not empty that is followed immediately by an empty one. Hence the no jumping stages rule :-)
Also, this requires an extra empty column after the last stage column (in your example, column E must be empty).
ps: added bonus, this formula also works for "no stage" rows ;-)

Resources