Excel: Get location of first and last non-zero cell in row - vba

The second row in the screen capture below (row 4 in my sheet) will sum up the values on each column and divide this sum by something. Those values can always change, and I'm trying to find a way to make a selection from the first non-zero value to the last non-zero value so I could use that range, to create a chart.
I am using elsewere =LOOKUP(2;1/(4:4<>0);4:4), which will return the last non-zero value of the row number 4, but I cannot use MATCH I guess because I might find other values equal to the last non-zero value, "earlier" in the range, and will not return the reference of that specific last non-zero cell.
I have tried =MATCH(0;4:4;1) to try to find the first non-zero cell, but this will return the location of the last zero cell for some reason.
Any ideas? VBA is also an option.

What I have been able to find:
First non-zero cell address: {=ADDRESS(4;MATCH(TRUE;4:4<>0;0))}
Last non-zero cell address: {=ADDRESS(4;MAX((4:4>0)*COLUMN(4:4)))}
I have added the { } to point out the fact that the formulas should be confirmed with CTRL + SHIFT + ENTER because they are Array formulas.
Hope it will help others!

Related

Excel 2016: IF function using position of cell relative to another cell

I'm trying to use IF to return a value that depends on the position of one cell relative to another in the same column.
Spreadsheet Example
If you click the above image, you'll see a number of columns with the possible values of "No," "Yes," "Yes>No," and "No>Yes."
The equation will go in the "Category of Change," row, one equation for each column. If the "Yes>No," is lower in the column than the "No>Yes," I want to return "Less Frequently," and if the opposite is true, I want to return "More Frequently" ("Same," if there is no "Yes>No," or "No>Yes").
I've tried using ARRAY and INDEX functions, but I'm not sure how to get Excel to "look" for each of those values, and then compare their ranking in the column.
Thank you in advance for your help!
MATCH will return the relative row number. This assumes the first column of data is in E2:E8.
=IFERROR(IF(MATCH("Yes>No",E2:E8,0)>MATCH("No>Yes",E2:E8,0),"Less Frequently","More Frequently"),"Same")
It is looking for exact matches, so if you have typos, it will always default to Same. If only one is found then it will still produce Same
You would put int he first cell and copy/drag over, the references will change automatically.

Count number of times data is repeated in a column and show number in another column?

I have a UserForm that finds and copies a range of data and pastes it along with new data from the UserForm into a different sheet. I am wanting for it to also count the number of times some of that data is repeated in the new sheet. I have tried several different approches but none are working. Right now this is what I have:
.Range("I1").Value = iVal = Application.WorksheetFunction.CountIf(Range("A3:A103"), "CrisisNameTextBox1.Value")
This puts "TRUE" in the corresponding cell instead of the number of times the data is repeated.
You probably could use this function in the corresponding cell:
=COUNTIF( [range], [cell] )
The [range] is the range you want to check (use $ to make sure its value does not change from one cell to another)
The [cell] is the cell you are currently checking.
Assign the function to the cells you want and it should work
If you want to drag/copy this formula from one cell to an other : use the $ character to lock the coordinates you don't want to be changed. I.e :
$A1 Will prevent the column from being changed, but will allow the row
A$1 Will prevent the row from being changed, but will allow the column
$A$1 Will prevent both coordinates from being changed
The same applies to ranges ($A1:$F15, $A1:F1, $A$1:F15, A1:$F15, etc.)

VBA Hide Row in table if Specified Column is Empty

I am trying to add to a macro I have that will hide every row that has no text in a column named Authorization. Please see the code I have below, I thought this may be on the right track but it does not hide any rows.
Cells.EntireRow.Hidden = False
For Each cell In Range("Authorization").End(xlUp)
If cell = "" And cell.Offset(1, 0) = "" Then cell.EntireRow.Hidden = True
Next cell
Edited to add how to define a dynamic named range
It is the fact that you have set the whole column to the name "Authorisation" that I think makes your code freeze, because the whole column is 1 million rows (if you have 2007 or above), and the code will still check even blank rows, so its doing it 1 million times. 1 Option is to rather than set it to the whole column, you could use a "Dynamic Named Range" which will expand and grow as data is added. There are several different formulas to do this, but based on the fact your data may contain blanks, this version of the formula will expand down to the last populated row in the column. My example uses colum A as you havent specified what column you are using, so change A to suit your needs.
You need to open the Names manager, from the Formulas tab
From the dialog box, find your "Authorisation" name.
Select it and you should see its current formula at the bottom of the dialog box, replace that with the following formula:
=OFFSET(Sheet1!$A$3,0,0,MATCH("*",Sheet1!$A:$A,-1)-2,1)
In the above formula:
Sheet1 is my sheet, replace it with yours a needed
$A$3 is the starting row of the name, so based on your comments, have set this as column A row 3
0,0, Are defaults you should not need to change
$A$A$ is the column it is counting values, so change as required
-1 is a default, leave as is
-2 is subtracting 2 from the count because we are starting on row 3, so if you change the starting row, change this
the last 1, defined how many columns your named range covers, in your example it is just 1, so this should not need changing.
Once you have defined the name in this way, the code below should work a lot quicker as it will only loop through down to the last row of entered data. There is one possible issue I can see with this and that is if the very last cell in column A is blank, but the rest of the row isn't, this will miss out the last row. I could fix this by using a different column to count what constitutes the last row, but need to know whicj column would always have a value in it.
< Original answer and code>
not sure you code matches the description of what you want it to do, namely you seem to be trying to check the row beneath the current cell as well, is this what you really wanted? Anyhow your syntax is slightly wrong. I have written and tested this and it works, I have swapped your offset around so my code is checking the cell in the named range "Authorisation" and then also checking the cell to the right. Amend to suit your needs
Sub test()
Dim c As Range
For Each c In Range("Authorisation").Cells
If c.Value = "" And c.Offset(0, 1).Value = "" Then c.EntireRow.Hidden = True
Next c
End Sub

Excel Macro - Search Range of Cell for 0, then return "empty" cell

This is my first time using this forum, and my VBA skill is not very well developed. I hope someone can help.
I have two columns of data, Column A and Column B.
Column A - Returns a sequential "month-year" or 0. If spreadsheet current date (=now()) is less than say Feb, then the cell for February returns 0.
Column B - I want this column to check each cell in Column A. If Column A cell has a date identifier, I want this to be placed in Column B. If Column A has a 0 identifier, I want Column B to return an "empty" cell.
Reason why I am doing this is I am graphing a bar chart. When I trick the program into making an empty cell (x-axis) the graph does not show any data for that month (which is what I want). Trying to make a dynamic graph, but I have no experience in VBA (only C programming =/).
You don't need VBA (or even formulas) to do this.
Highlight Column A (the entire column), copy it.
Highlight Column B (the entire column, right click, Paste Special, select values and number formats, okay.
Highlight Column B again. Press Ctrl+H, Type 0 (or failing that it might be 00/01/1900) in the 'find what', leave the 'replace with' one blank. Tick Match entire cell contents. Click replace all.
Done.
Instead of trying for an empty space (which would be impossible, as there's a formula in that cell), use an error condition.
Use this formula, and copy down:
=IF(A1=0,NA(),A1)
This will return the error condition #NA! and Excel will leave the column blank
The other way would be to have a dynamic range for the chart data - I have a chart that will adjust to 5,6 or 7 days, depending on the data returned for the week. The Horizontal (Category) Axis Labels is set to a named range (='Sample.xlsx'!LastWeekRange) and the range checks the data, and returns the appropriate number of cells.
LastWeekRange is defined in Name Manager as =OFFSET(Data!$A$3,0,0,IF(Data!$F$9>0,7,IF(Data!$F$8>0,6,5))), which returns A3:A7 if there's nothing in F8, A3:A8 if there is something in F8 but not in F9, and A3:A9 if there is something in F9.

For each cell in a range, if a value in a seperate range is found in the next cell do stuff

This Macro I have built works but I am hoping for a faster version or a Formula that will do the same in less time.
What I Have:
For Each cell In Range("Table_Query_1[[#Data],[Reason2]]")
For Each PossibleValue In Range("F2", Range("F2").End(xlDown))
If Len(cell) = 0 Then
If (InStr(UCase(cell.Offset(0, 1)), UCase(PossibleValue)) <> 0) Then
cell.Value = PossibleValue.Value
End If
Else
Exit For
End If
Next
If Len(cell) = 0 Then
cell.Value = cell.Offset(0, -1)
End If
Next
The only other way I could get anything to work way with the following Array Formula
=IF(ISNA(MATCH($F$3:$F$10,[#Extra Info],0)),[#Reason],$F$3:$F$10)
but this doesn't work for Partial matches as in the case of Row 4 and 9. I also have my doubts that this array formula would be that much faster then a vba macro along with the fact it would also require more upkeep with the test values range (F2:f3) in this case as I would have to constantly update that formula OR I wouild have to make the original range like F2:F100 witch would cause it to take that much longer.
So, what i'd like is if ANY value in my range of values (F2:F3 in this case), Is found inside of the Extra Info Column on the current Row , Then Reason2 of that row (Offset(0, -1)) equals the Value that was matched. But if nothing is found then just use the Reason in that row(Offset(0,1)).
And the second Issue is that I need the Macro to Run After the QueryTable refreshes but if I set it as a Cell Change Event on a cell the is in the query that will change, the macro runs and finishes before the Final querytable is imported and sorted.
Solved!
This is post the comment that I posted above which had the initial formula.
=IF(COUNT(FIND($F$2:$F$3,C1)),"What Will Go Here",A1)
The below tells you what has to go in place of "What Will Go Here"
Put this formula in cell B2. Note that this is an Array Formula. You will have to press CTRL + SHIFT + ENTER after you enter the formula.
=IF(COUNT(FIND($F$2:$F$4,C2)),INDEX($F$2:$F$4,MATCH(SUM(IF(ISNUMBER(--FIND($F$2:$F$4,C2,1)),--FIND($F$2:$F$4,C2,1))),FIND($F$2:$F$4,C2,1),0),0),A2)
Screenshot
Explanation:
FIND($F$2:$F$4,C2,1) when used with an array returns an array. To check the values you can highlight it and press F9 and it will tell you the position at which the match is found. See this screenshot
So it tells us that it found the match at the 3rd position in 4532. It yet doesn't tell us with what did it find a match.
Now the next step is to retrieve the position of that number from the array. So in the above example it will be position 2 and to find that position we will use MATCH() and to use MATCH we will need that 3
So to retrieve 3 from the array we use this formula
=SUM(IF(ISNUMBER(--FIND($F$2:$F$4,C2,1)),--FIND($F$2:$F$4,C2,1)))
Now we have that 3 so we will use it in Match to find the position in the Possible Value
=MATCH(SUM(IF(ISNUMBER(--FIND($F$2:$F$4,C2,1)),--FIND($F$2:$F$4,C2,1))),FIND($F$2:$F$4,C2,1),0)
This will give us 2
Now we know the position of the number in the Possible Value. To find that number we will use INDEX
=INDEX($F$2:$F$4,MATCH(SUM(IF(ISNUMBER(--FIND($F$2:$F$4,C2,1)),--FIND($F$2:$F$4,C2,1))),FIND($F$2:$F$4,C2,1),0),0)
SAMPLE Workbook
http://wikisend.com/download/280280/Sample.xlsx
This is a solution I came across that does not have to be Array Entered and seems to run faster then Siddharth Rout's solution. I am using the formula
=IFERROR(LOOKUP(1E+100,SEARCH($F$2:$F$4,C2),$F$2:$F$4),A2)
Where I am looking for any word in C2 that is in the range F2:F4. If none found it will throw an ERROR and in that situation I know nothing was found and simply return the original reason.
Not shown in the picture I also turn F2:F4 into a named range called Reasons and change the formula too:
=IFERROR(LOOKUP(1E+100,SEARCH(Reasons,C2),Reasons),A2)