EXCEL-VBA Change a range with a loop - vba

Set rng = Worksheets("Sheet1").Range("B2")
I have the above and would like to run a loop that changes the range I use/evaluate. I have tried variations of the following.
for x = 2 to 10
Set rng = Worksheets("No-Funding").Range(x & "2")
Next X
I have done some investigating and found this other Stack Overflow: Excel VBA Looping formula to change Range I can not make sense of it in this situation though.
My code will not work if it uses cells either, I have tried that and can only make it work with Range. Thanks for any help provided!

For a strictly numerical increment try,
Set rng = Worksheets("No-Funding").Cells(x, 2)
An xlA1 style reference can be achieved by factoring in the ASCII character.
Set rng = Worksheets("No-Funding").Range(Chr(64 + x) & 2)

Try this:
For x = 2 To 10
Set rng = Worksheets("No-Funding").Cells(2, x)
Next x
As far as I know it is no matter for VBA if you use function .Range or .Cells, since both of them return object or Range type.

Use
Set rng = Worksheets("Sheet1").Range("B2").Offset(0,x)
to move to a different column. Better yet
Dim values as Variant, rng as Range
Set rng = Worksheets("Sheet1").Range("B2").Resize(10,1)
values = rng.Values2
For i=1 to 10
values(i,1) = 2*values(i,1)
Next i
rng.Values2 = values

Related

VBA Range.Find method not finding a value that IS in the range

I have the following method which finds the largest and smallest values in a range. I am then using those values to locate the actual cell they are in as I need to grab the value from the header cell of that column. The Range.Find is always returning Nothing even though the range being searched HAS A CELL WITH THAT VALUE.
Sub GetTopAndBottomFiveCommodities()
Dim tempRange As Range, x As Integer, bestPnL As Double, worstPnL As Double
Dim strTopRangeName As String, strBottomRangeName As String
Dim cCell As Range, commodityName As String
Set tempRange = dataSourceSheet.Range("A:A").Find(What:="Year Totals")
Set tempRange = Range(tempRange.Offset(0, 1), tempRange.End(xlToRight).Offset(0, -1))
For x = 1 To 5
strTopRangeName = "TopCommodity" & CStr(x)
strBottomRangeName = "BottomCommodity" & CStr(x)
bestPnL = WorksheetFunction.Large(tempRange, x)
worstPnL = WorksheetFunction.Small(tempRange, x)
Debug.Print tempRange.Address
' get the top commodity name and PnL
**Set cCell = tempRange.Find(What:=bestPnL, LookIn:=xlValues)**
commodityName = dataSourceSheet.Cells(5, cCell.Column).Value
Range(strTopRangeName).Value = commodityName
Range(strTopRangeName).Offset(0, 1).Value = bestPnL
Next x
End Sub
The code line
Set cCell = tempRange.Find(What:=bestPnL, LookIn:=xlValues)
is always returning nothing but I have verified that there are cells with that value. One example, the cell value is 66,152.61 (displayed in cell as 66,153) and the bestPnL variable is 66,152.61 , so I tried rounding bestPnL to 66,153, but still didn't find it. The debug statement is showing tempRange has the right range, so its not searching in the wrong place.
The only thing I can think of is the cell with the value, gets its value from a very long formula, using over a dozen named ranges, can this be fouling the find method?
Just so we all know I'm not crazy, here is a snapshot of part of the range I'm searching where I'm testing.
EDIT
Based on Tim Williams suggestion, I changed the number format of the range being searched prior to the Find call.
tempRange.NumberFormat = "0.00"
and then the Find call works as it should. I then just put the number format back the way I want it at the end of the routine.
tempRange.NumberFormat = "$#,##0;[Red]$#,##0"
Works as expected now.
Try removing the thousand separator from the number format on the cells. When I did that in a test range it worked fine, but with the separator it failed to find the value.
Set f = rng.Find(what:=bestPnL, LookIn:=xlFormulas)
will work even with the thousand separator (EDIT: only works with hard-coded values; fails with formulas).
EDIT2: this worked for me with a thousands separator and using formulas for the values (EDIT3!: does not work with currency formatting).
Sub Tester()
Dim f As Range, v, rng As Range
Set rng = Range("C3:C21")
v = Application.Large(rng, 3)
v = Format(v, rng.Cells(1).NumberFormat)
Set f = rng.Find(what:=v, LookIn:=xlValues)
Debug.Print f.Address ' >> C19
End Sub
This is an old question, but I found an alternative that can be effective and simple in some situations:
dim idx as long, rng as range
set rng = someRange
idx = application.WorksheetFunction.Match(1234,rng,0)
This will return the relative position of the FIRST 1234 valued cell in the provided range, independently of the formatting. The last 0 means you use an exact match.

Range Error - Loop to increase row index vba

This is a portion of my code. In the end, I want to loop through cells, find the text in between two phrases, concatenate that, and paste it into determined columns. Once the code finds "ID", it will add a row to the paste range, and start over. (this is near the bottom).
What I can't do, is get the range in each section to cooperate. When I use 'wksSource.Range(Cells(R, 2)).Value = stringValues' it throws the error: 1004, Method range of object worksheet failed. But if I use 'wksSource.Range("B15").Value = stringValues' it is completely fine. The problem is, that isn't dynamic. I need 'R' to increase everytime the phrase "ID" is found. The columns will be constant for each section. (R,2) (R,3) etc.
I've done so much googling and I understand why that error is thrown; I just can't figure out why it's happening in this instance. Worksheet is defined... and it works with "B15", so I'm thinking the error is in the "R", but I am stuck.
Please help! (I realize this could probably be a loop all the way, and I'd love to hear advice on that if you want, but for now, I am trying to learn and it seems the best way for me to do that is one piece at a time. Increase rows with a small loop today, tackle big loops tomorrow. :))
Dim rng As Range, AllPos As Range, rngEnd As Range, rngStart As Range
Dim DeptRng As Variant, stringValues As String, cell As Range, NextRow As Variant
Dim R As Integer, lastRowCon As Integer, wksSource As Worksheet, paste As Range
Set AllPos = Range("A2:A53")
R = 2
Set wksSource = ActiveWorkbook.Sheets("Sheet1")
Set rngStart = AllPos.Find("Department Description:").Cells
If Not rngStart Is Nothing Then
Set rngEnd = AllPos.Find("Position Duties :").Cells
Set DeptRng = Range(rngStart, rngEnd.Offset(1))
For Each C In DeptRng
stringValues = stringValues & C
Next C
wksSource.Range(Cells(R, 2)).Value = stringValues
stringValues = ""
End If
.....several iterations of above here.....
Set rngStart = AllPos.Find("ID:").Cells
If Not rngStart Is Nothing Then
'Finds last row of content
lastRowCon = wksSource.Range("A1").End(xlDown).Row
'Finds first row without content
R = lastRowCon + 1
'select next empty row, Column B
End If
wksSource.Cells(R, 2).Value = stringValues
If it's a single cell, you don't need Range().
Edit: See this for further examples. If you give the Range property one parameter, it has to be the name of a Range. Cells(i,j) returns a Range object and you don't need/can't use Cells(i,j) as a name of itself. When you use Cells(i,j) it's like using ActiveSheet.Cells(i,j), btw.

Set a range to an entire column with index number

I'm building a function that takes a column number as an input to return the highest value in the column.
I need to work with an entire column with a column index number. The following code works but I need an index number instead of using "B:B" to reference the column.
Set rng = Range("B:B")
When I use the following code, everything seems to break down. It always returns a 0 even though the highest number is 44. Can you see what I am doing wrong? It worked perfectly when I used "B:B" as a range.
Set rng = Range(Columns(2),Columns(2))
It doesn't seem to recognize anything in the range. Any help would be awesome!
Try this
Sub Sample()
Dim Rng As Range
'~~> This will let you work with Col B
Set Rng = Columns(2)
'~~> This will give you the Max in that column
MsgBox Application.WorksheetFunction.Max(Rng)
End Sub
This is from a solution I found a while back:
Dim x, y As Int
Dim rng As Range
x = 1 ' For A
y = 4 ' For D
Set rng = Columns(Chr(64 + x) & ":" & Chr(64 + y))
Source: http://www.mrexcel.com/forum/excel-questions/114025-visual-basic-applications-select-multiple-columns-using-column-number.html

optimizing looping through rows and columns of an array

I have an array of about 400 columns and 30 rows
I want to go through all the columns and each row in every column, and test cell of each cell for something..like if it's holds a negative number, and if it does I want to copy the cell itself and certain cells above it to another sheet.
I have done this with 2 standard "for-loop", however it takes a lot of time and there are more than 10 different tests for each cell.
I was wondering if anyone knew a more efficient way of doing this, such as using "for each" statements...I've been trying this with no luck -
Set FinalSht = ActiveWorkbook.Worksheets("Final")
Cnter = FinalSht.Cells(5, FinalSht.Columns.Count).End(xlToRight).Column
Rowter = FinalSht.Cells(FinalSht.Rows.Count, "B").End(xlUp).Row
Set AnRe = ActiveWorkbook.Worksheets("Anomaly")
AnRe.Cells.ClearContents
Set SRng = FinalSht.Range(FinalSht.Cells(5, 3), FinalSht.Cells(14, Cnter))
RowCount = 0
ColCount = 0
For Each RowRng In SRng.Rows
RowCount = RowCount + 1
For Each ColRng In SRng.Columns
ColCount = ColCount + 1
Select Case True
Case FinalSht.Cells(RowRng.Rows, ColRng.Columns) < 0
With AnRe
.Cells(RowCount, ColCount).Value = FinalSht.Cells(RowRng.Rows, ColRng.Columns).Value
End With
End Select
Next ColRng
Next RowRng
thanks for any help I can get...
A few general things to check if your code is slow:
Declare your variables to fit your data, see here for more info
Get rid of unused variables, code parts
Check out this for some ideas on how to use the for each loop (you don't need two for each loops to go through all cells in a range). For each is generally faster than for loops.
You really need to optimize your loops: make sure you only loop through what you really need to.
Also, optimize whatever is inside your loops. Make sure you are only doing whatever is necessary to do inside the loop, because that is what matters.
About your code:
Basically your code was slow because of two things.
Cnter = FinalSht.Cells(5, FinalSht.Columns.Count).End(xlToRight).Column
That xlToRight made it loop through 16000+ columns, instead of just 400. Big difference. All the rest I'm telling you is just 1% of the speed gain. When you are debugging a code, step through it with F8, and use watches or the locals window. More info here.
The other problem was having two for each loops instead of just the one you actually need.
The below code took less than a second to run. Hope this helps.
Sub test()
Dim Finalsht As Worksheet
Dim AnEr As Worksheet
Dim Cnter As Integer
Dim Rownter As Long
Dim SRng As Range
Dim myCell As Range
Set Finalsht = ActiveWorkbook.Worksheets("Final")
Cnter = Finalsht.Cells(5, Finalsht.Columns.Count).End(xlToLeft).Column
Rowter = Finalsht.Cells(Finalsht.Rows.Count, 2).End(xlUp).Row
Set AnRe = ActiveWorkbook.Worksheets("Anomaly")
AnRe.Cells.ClearContents
Set SRng = Finalsht.Range(Finalsht.Cells(5, 3), Finalsht.Cells(14, Cnter))
For Each myCell In SRng
Select Case True
Case myCell.Value < 0
With AnRe
.Cells(myCell.Row, myCell.Column).Value = myCell.Value
End With
End Select
Next myCell
End Sub

Setting up a dynamic range in excel-vba

I'm basing my code off of this.
Excel VBA - select a dynamic cell range
I'm trying to find the syntax to create a dynamic range. Example: I always start on D8 but the upper bound of the range is based on an int count in another cell. [h4]
Dim count As Integer
count = Sheet2.Cells(8,1).Value
Set refRng = Sheet2.Range("D8:" & Cells(8, i).Address)
Is the relevant code sample.
I now know that Sheet2.Range("H1") doesn't return an int, it returns a variant or something?
I've tried a million different things and have figured out that none of them work. There has to be a better way to set up a dynamic range.
Not 100% sure what you're trying to achieve but in terms of messing around with ranges maybe this is a start:
Option Explicit
Sub select_Range()
Dim count As Integer
count = ThisWorkbook.Worksheets("Sheet2").Range("A8").Value
Dim i As Integer
i = count
Dim refRng As Excel.Range
Set refRng = ThisWorkbook.Worksheets("Sheet2").Range("D8:D" & i)
refRng.Select
End Sub
This results in the following on Sheet2:
This was originally a comment, but it is also the solution so I am adding it as an answer
Cells(8, 1) = "A8". If you want cell H1 it would be Cells(1, 8) or Cells(1, "H"). If you want cell H4 it would be Cells(4, 8) or Cells(4, "H").
Alternately, just Range("H1") or Range("H4")