Find last cell with function output data and output new result - vba

This problem uses the following data, which would be manually adaptive over a fixed cell range--with each cell in the B column range containing a formula. It aims to find the last data cell from the underlying formula cells.
I would like to find the last formula cell with data within the formula range B2:B11, and create a dynamic median from this last cell with the four cells above it. The median should be output to cell F6--result of 9. This is a dynamic exercise. Any thoughts on how to do this most efficiently, given the code below?
Sub OutputMedian()
Dim FunctionRange As Range
'Represents a fixed range with function in B2:B11
Set FunctionRange = Worksheets("Sheet1").Range("B2:B11")
'Must start median calc from B9, as it's the last cell with function output data
'Must store Median from last data cell, using 5 cell offset (see output from cell F2)
'Must output the Final (e.g., median output of 9 here) to cell F6
End Sub

See: Excel VBA: Get Last Cell Containing Data within Selected Range
My modified answer by #brettdj from above question (referred by #varocarbas). Thanks!
Got it to work!! Outputs the correct dynamic median, with five periods set from -4 Offset below.
Sub OutputMedian()
Dim WS As Worksheet
Dim rng1 As Range
Dim rng2 As Range
Set WS = Sheets("Sheet1")
Set rng1 = WS.Columns("B:B").Find("*", Range("B1"), xlValues, , xlByRows, xlPrevious)
Set rng2 = rng1.Offset(-4, 0)
Dim FirstCell As String
Dim LastCell As String
FirstCell = rng2.Address(0, 0)
LastCell = rng1.Address(0, 0)
Dim CellResponse As String
CellResponse = Evaluate("=median(" & FirstCell & ":" & LastCell & ")")
Range("F6").Value = CellResponse
End Sub
Better way to use objects (e.g., R1C1, Cells) in creating dynamic functions--i.e, without passing function into Evaluate as concatenated strings?

Related

Clear Excel Cell if Value less than another Cell value

I am hoping someone can help, I need to clear cells when then value of is less that a value in another cell. I did use conditional formatting but this messes up calculations further into the sheet.
I used a guide and was able to remove cells when I inputted the fixed integer into the module but am unsure how I adapt this to refer to a cell instead of a fixed number.
Thank you.
Ed
I believe this is what you are looking for below, this will take a value from cell B1 and compare against values in Column A, and if the values are less than the value in B1, it will clear the contents of that cell:
Sub ClearLowerThan()
Dim c As Range, Rng As Range
Dim LastRow As Long
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare you worksheet, amend as required
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'get the last row with data on Column A
CompareVal = ws.Range("B1").Value
'get the value to compare against, in this case from cell B1
Set Rng = ws.Range("A1:A" & LastRow)
'set the range to compare against the value from B1
For Each c In Rng 'for each cell in the given range
If c.Value < CompareVal Then c.ClearContents
'if value of cell is less than the value to compare against, clear the cell contents.
Next
End Sub

Excel VBA Fining Last Row of Filtered Range

I am trying to find the number of rows of a filtered range on a sheet. LstRow2 is the variable I am trying to find. With this code I am getting the unfiltered number of rows.
CSht.Range(CSht.Cells(1, 1), CSht.Cells(LstRow1, LstCol1)).AutoFilter Field:=2, Criteria1:="RA"
With CSht
LstRow2 = .UsedRange.SpecialCells(xlCellTypeLastCell).Row
End With
You'll need to work with the visible cells only, since it's filtered.
Try this:
With CSht
'load filter cells into Range object
Dim rngFilter as Range
Set rngFilter = Intersect(.UsedRange,.UsedRange.Offset(1)).SpecialCells(xlCellTypeVisible)
'find the max number of elements split by $ in the range address
'needs to be dynamic because of areas
Dim lUpper as Long
lUpper = UBound(Split(rngFilter.Address,"$"))
'the last element will be the last row in the filtered range
'the last number in the rngFilter.Address
Dim LstRow2 as Long
LstRow2 = Split(rngFilter.Address,"$")(lUpper)
End With
Why don't you replace this line
LstRow2 = .UsedRange.SpecialCells(xlCellTypeLastCell).Row
With
LstRow2 = .Cells(.rows.count, 1).end(xlup).row
There may be several areas after filtering so you need to use Areas. Great explanation here https://stackoverflow.com/a/17287558/3733214. This should work:
Dim Line as Range
For Each Line In CSht.UsedRange.SpecialCells(xlCellTypeVisible).Areas
LstRow2 = LstRow2 + Line.Rows.Count
Next
Credits: https://www.mrexcel.com/board/threads/vba-code-to-count-visible-rows-after-autofiltering-a-table.602866/post-2988416
This formula lastRow = Worksheets("Sheet1").Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row has given me the the correct last visible row of a filtered range.
Current region will do it for you in a single line
LastRow = sht.Range("A1").CurrentRegion.Rows.Count

Define range based on the value of another cell

Is it possible to define a range in VBA based on a value given in a cell?
For example, I have a dataset with four columns and a constantly changing number of rows. I have the number of rows in cell F2. Suppose cell F2 indicates the number of rows is 385, then I be able to Range("A1:D385").Select, but I want the selection of the last cell to be dependent on cell F2.
So if I change F2 to 50, that the next time I run the macro, A1:D50 will be selected, but since I'm new to VBA I can't figure it out.
The most proper way to do this would be like this
Sub getRng()
Dim Cval As Variant
Dim Rng1 As Range
Cval = ActiveSheet.Range("F2").Value
Set Rng1 = ActiveSheet.Range("A1:D" & Cval)
End Sub
this sets Rng1 as an object that you can use later on in another function
such as
Rng1.Select
or
Rng1.Copy
This is what you are looking for:
Dim lastRow As Integer
With ThisWorkbook.Sheets(1)
lastRow = .Cells(.Rows.Count, "F").End(xlUp).row
.range("A1:D" & lastRow).Select
End With
The code looks for the first non-empty cell in column F, from bottom to top. Similar to selecting the last cell in column F and pressing Ctrl + up-arrow.

Copy and pasting information within a for loop

I would like to create a function that copies certain excel ranges in worksheets and paste these ranges into a "motherfile".
Now, I am trying with this code:
Sub ranges()
Dim month As Variant
Dim months As Variant
months = Array("V01 DEN HAAG", "V02 AMSTERDAM")
Dim destinationRange As Excel.range
Set destinationRange = Sheets("DATASET").range("B3").End(xlDown).Offset(1, 0)
For Each month In months
Dim sourceRange As Excel.range
Set sourceRange = Sheets(month).range("H7", range("H7").End(xlToRight))
Call sourceRange.Copy
Call destinationRange.PasteSpecial
Next month
End Sub
But, I get an Application-defined or object-defined error. Any thoughts on what goes wrong? Thanks!
Adding to mielk's anwser the problem is in the codeline:
Set sourceRange = Sheets(month).range("H7", range("H7").End(xlToRight))
This is because if you are collecting from multiple sheets data and you use range("H7").End(xlToRight it will search for this on the active sheet. Therefor it can only find the correct range if its on the correct sheet.
by using the following code:
Set sourceRange = Sheets(month).Range("H7", Sheets(month).Range("H7").End(xlToRight))
it will work no matter which sheet is active at that moment.
another addition is you can copy and paste in 1 code line:
sourceRange.Copy Destination:=destinationRange
see below the entire code:
Sub ranges()
Dim month As Variant
Dim months As Variant
months = Array("V01 DEN HAAG", "V02 AMSTERDAM")
For Each month In months
Dim sourceRange As Excel.Range
Dim destinationRange As Excel.Range
With Sheets("DATASET")
Set destinationRange = .Cells(.Rows.Count, 2).End(xlUp).Offset(1, 0)
End With
Set sourceRange = Sheets(month).Range("H7", Sheets(month).Range("H7").End(xlToRight))
sourceRange.Copy Destination:=destinationRange
Next month
End Sub
The possibly reason for this error is that you don't have any values in worksheet "DATASET", column B, below 3. row.
Look at this line of code:
Set destinationRange = Sheets("DATASET").range("B3").End(xlDown).Offset(1, 0)
First it takes the range from cell B3 to the last cell in this column (B1048576 in Excel 2007+).
After that it tries to offset this range by one row down (so it tries to create a range having the same number of rows and columns but starting one cell below).
However, it is not possible, because such range would have to start in cell B4 and end in cell B1048577 and Excel has only 1048576 rows.
If you want to assign the first empty row to the variable destinationRange you should replace this code:
Set destinationRange = Sheets("DATASET").range("B3").End(xlDown).Offset(1, 0)
with the below:
With Sheets("DATASET")
Set destinationRange = .Cells(.Rows.Count, 2).End(xlUp).Offset(1, 0)
End With
Both those statements are similar. The difference is that the second one
starts from the last cell in the column B and look for the first non-empty
cell above.

Find cells with same value within one column and return values from separate column of same row

I want to find all the cells in Column L with a particular value and return the values in Column D of the same row as those cells found.
So far, I am only able to return one result, which would be the top most result in my list, but I want to find all the rest as well, which I don't know the code to use.
Just to further explain: Value in cell D11 is the value I want to find in Column L of sheet "Master List". Supposedly I find the value in cells L13, L15 and L20, I want to return the value in cell D13, D15 and D20 into cells "C37:C39" of ws. Note: no. of cells that have the value may vary so the values returned will just appear from C37 downwards (something like automatic multiple selection, copy and paste)
Here's a little something to start the ball rolling:
Sub FindRelatedProducts()
Dim cell As Excel.Range
Dim D11Value As Variant
Dim D11Row As Variant
Dim ws As Worksheet: Set ws = Sheets("RShip")
Set cell = ws.Range("D11")
D11Value = cell.Value
With Sheets("Master List")
D11Row = Application.Match(D11Value, .Range("L:L"), 0)
If Not IsError(D11Row) Then
ws.Range("C37") = .Range("D" & D11Row).Value
End If
End With
End Sub
Here's an example using range variables.
You'll want to define a range for the input data range and a range for the output data. Then in the VBA you will want to change the wrk, inRng and outRng variables to be the named ranges you defined and change the column indexes in the for and if blocks to match the column index of the data you are looking for.
Option Explicit
Option Base 1
Sub FindValues()
Dim wrk As Worksheet
Dim inRng As Range
Dim outRng As Range
Dim cntr As Long
Dim outCntr As Long
Dim findVal As Double
Set wrk = Worksheets("Data")
Set inRng = wrk.Range("LookupRange")
Set outRng = wrk.Range("OutputRange")
' Clear the output range in case you have fewer values on this run than on the previous one
outRng.ClearContents
' Set the value you are looking for
findVal = 1
' Iterate through the rows in the input range. If you find the result you want then write it to the output range
For cntr = 1 To inRng.Rows.Count
If inRng(cntr, 1) = findVal Then ' Assumes the value you are finding is in column 1 of the input range
outRng(outCntr, 1) = inRng(cntr, 2) ' Assumes the values you are exporting is in column 2 of the input range
outCntr = outCntr + 1
End If
Next cntr
End Sub