I am trying to use a collection to set variables equal to 0 each time before they run through a sub. I have a bunch of metrics all as separate sub routines, and for each sub, I declare the variables as long and then set all of them equal to 0 and then have them pull from whatever data they need to. I'd like to be able to not have to set them equal to 0 every time, but rather set them equal at the beginning or something so it doesn't have to be put in in each subroutine, but I am unclear as to how to do that. I tried this code but I have no idea if it is even remotely right or where to put it:
Dim myVars As Collection
Set myVars = New Collection
Dim j As Variant
myVars.Add a
myVars.Add b
myVars.Add c
myVars.Add d
myVars.Add e
For j = 1 To myVars.Count
myVars(j) = 0
Next j
If you declare your variables as numeric types (eg. Long,Integer,Byte,Double,Single) then they're automatically assigned a value of 0.
You'd be better off with strongly typed variables in any case, and it would avoid the need for using a collection or making the variables global in scope.
Related
I have this code: there are two for loops from 1 to 10 in it. In each loop a variable k is declared.
Sub Test()
Dim i As Long
For i = 1 To 10
Dim k As Long
k = i * 2
Debug.Print k
Next
Dim j As Long
For j = 1 To 10
Dim k As Long 'error here
k = j * 2
Debug.Print k
Next
End Sub
However when I try to run it I get a duplicate declaration in the current scope error. I'm not sure why I get it - isn't a variable's scope limited by the loop, since it was declared within it? Is there any way to remove the remnants of the first variable so that it would be possible to create a variable with the same name in the second loop?
When you declare a variable in a procedure, this variable is valid for all the procedure, not only for the loops.
If you want to clear your variable, you can set k = 0
When a local variable is declared with the Dim statement, the variable remains in existence only as long as the procedure in which it is declared is running. Usually, when the procedure is finished running, the values of the procedure's local variables are not preserved, and the memory allocated to those variables is released. The next time the procedure is executed, all of its local variables are reinitialized.
https://support.microsoft.com/en-us/help/141693/scope-of-variables-in-visual-basic-for-applications
http://www.excel-easy.com/vba/examples/variable-scope.html
I have a range variable (called Constr) that is based on data that looks like this
Type Bound1 Bound2 Var1 Var2
X 1 2 3 4
Y 1 2 3 4
--
Z 1 2 3 4
I now use this procedure to change the selection to only the entries before the '--'
Sub Adjust_Selection(which As String, what_in As String, columns As Integer)
Dim row_nr_start As Integer
Dim row_nr_end As Integer
Dim row_nr_delta As Integer
Sheets("Main").Select
row_nr_start = Range(which).Find(what:=what_in, LookIn:=xlValues, LookAt:=xlWhole).Row
row_nr_end = Range(which).Find(what:="--", LookIn:=xlValues, LookAt:=xlWhole).Row
row_nr_delta = row_nr_end - row_nr_start
Range(which).Resize(row_nr_delta, columns).Select
This works and I can see that the selection changes, if I now call it using
Call Adjust_Selection("Constr", "Type", 5)
myitem("Constraints") = Range("Constr").Value
myitem is of type
Dim myitem As New Scripting.Dictionary
however when I access the value it still has everything in it. How can I update the value to only the first few lines up until the '--'?
You are calling Adjust_Selection with the named range Constr and afterwards refer to the named range Constraints. So, of course the result is different because you are referring to two different named ranges.
Furthermore, the named range Constr is not altered. It is merely used as a starting point and then a sub-set is Selected. But by selecting something you are not changing a named range (especially not a differently named range).
So, I am guessing that this is what you are searching for:
Call Adjust_Selection("Constr", "Type", 5)
ThisWorkbook.Names.Add Name:="Constraints", RefersTo:=Selection
myitem("Constraints") = Range("Constraints").Value
Note, that the selection of Adjust_Selection is now "saved" in the new named range Constraints and then myitem is being assigned this named range which is limited to the (correct) selection. Hence, the resulting variable (being a dictionary) contains all elements without the --.
Hi ThatQuantDude, I don't quite understand your question even after trying it out on my own. Based on the examples you gave, I assumed you want to store the selected range data into "Constraints" key? Apart from this, your sub function for selecting the range is working fine.
Call Adjust_Selection("Constr", "Type", 5)
myitem("Constraints") = Range("Constraints").Value
Appreciate if you could elaborate it further so I can better understand what you are trying to do? Thanks.
Range.Resize is a function. It will not change the range; it returns a new one. You just happen to select it, which isn't necessary. Turn your sub into a function returning the result of Range.Resize, and use this function directly on the right hand side of your assignment.
Note that you're not using the same name for your range in both lines of code, which I assume is a typo.
How do I get the length of character between beginning with space and ending with * Here is the image. Column B shows the total len before dasher(-) and my code
Sub xn()
Dim x As Integer
x = 1
If Worksheet("Sheet1").Range("A"& x).len(Right," ") Or _
Worksheet("Sheet1").Range("A"&x)len(Left,"-") Then
len(totallen)
End If
x = x + 1
End Sub
The code posted has multiple issues:
Worksheet is not a valid object - you need to use Worksheets.
.len is not a property of a Range object.
Even in .len was a property of a Range, you would need a
de-reference operator (aka '.') in here: Range("A"&x)len(Left,"-")
If you intend to use the function Len(), it only takes one argument.
You apparently are trying to loop, but you need to use either a For
or For Each loop - it won't loop automatically when you increment x
at the bottom of the sub.
Right is a function, but you're calling it without arguments and they are not optional.
Similarly, Left is a function, but you're also calling it without
the required arguments.
totallen is not declared anywhere, so Len(totallen) will assume
that totallen is a Variant (default for undeclared variables), then
cast it to a String, and then always return 0 because it has never
been given a value.
Anything else I may have missed.
The solution is to use the InStr function. It returns the location in a string of a given sub-string.
Sub xn()
Dim x As Long
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Worksheets("Sheet1")
For x = 1 To sheet.Range("A" & sheet.Rows.Count).End(xlUp).Row
sheet.Cells(x, 2) = InStr(1, sheet.Cells(x, 1), "-") - 1
Next x
End Sub
I'd also recommend taking a look at the MSDN article on Looping Through a Range of Cells (2003 vintage, but still valid), and Error Finding Last Used cell In VBA.
Hello I am new to VBA and I am trying to iterate over a collection i've made and execute an action for each value.
Here is my code:
Sub makeRowsMatch()
Dim rows As VBA.Collection
Set rows = New VBA.Collection
Dim i As Integer
Dim j As Integer
Dim y As Integer
For i = 2 To 22203
For j = 2 To 121
If Cells(i, 2).Value <> Cells(j, 38) Then
rows.Add (i)
End If
Next j
Next i
For Each y As Object in rows
rows(y).Delete
Next y
End Sub
I keep on getting an error in the line:
For Each y As Object in rows
It keeps on getting highlighted yellow, but when I remove the above line is get the following error:
For Each control variable must be Variant or Object
Could someone explain why it is not letting me iterate over the values?
The whole issue of declaring variables is new to me.
Thanks!
Declare y as Variant, i.e.:
Dim y As Variant
and change your loop like this:
For Each y In rows
Then the loop will work or, at least, it won't give you an error at that point.
But the next problem/error is inside the loop. This line:
rows(y).Delete
will give you an error "Object required", or something like that, because rows(y) return an Integer, so you can't call Delete on it. There's some confusion here because rows on its own means the Rows range of the active sheet. But you also named your collection as rows, so there's a naming conflict.
Rename your rows to, for example, myrows and it should then all work. However, I don't know what you're trying to do with the Delete line, so I can't advise further.
You've got a conflict in your declarations and use. This line declares y as an Integer, clearly:
Dim y As Integer
But you then try to use it as an Object, either with
For Each y As Object in rows
or
For Each y in rows
Change the declaration to
Dim y As Object
(I'm not that familiar with VBA. If the above doesn't work, change the declaration to Dim y As Variant instead.)
As a noobie to VBA, I am having a Hell of a time understanding how arrays, dynamic arrays in specific, work. I am an Industrial Engineering student, so most of my coding has been done with MatLab.
My question is: Why do I keep getting Run-time error '9' "Subscript out of range" for the following code:
Sub FunWithArrays()
Dim DynArray()
Dim i As Integer
Dim j As Integer
j = 1
For i = 1 To 10
DynArray(j) = i
j = j + 1
ReDim DynArray(UBound(DynArray) + 1)
MsgBox DynArray(i)
Next
End Sub
Any and all help is appreciated!
As people in the comments have mentioned, dynamic arrays are just that: dynamic. That is to say that if you declare an array without dimension, as you have here with Dim DynArray() then it doesn't at this point have any "slots" to store anything.
When an array is declared this way, you then need to Redim it to tell it how many slots you want it to have (presumably after determining this from some other data or user input).
The full code for this would be:
Sub FunWithArrays()
Dim DynArray()
Dim i As Integer
Dim j As Integer
j = 1
Redim DynArray(10)
' redimensioned the array to hold 10 items (since
' you've set the loop as i=1 to 10 you must already
' know that the array wants to hold 10 things)
For i = 1 To 10
'ReDim Preserve DynArray(i)
' this is how you could do it if you didn't know in
' advance that you were going to loop 10 times,
' but as somebody else said, this is a slow way to do it.
DynArray(i) = j
j = j + 1
MsgBox DynArray(i)
' Generally instead of a messagebox here I would use:
' Debug.Print DynArray(i)
' this then prints out the value (on a new line each time)
' into the immediate window which means you can see the
' output without having to click "OK" each time.
Next
End Sub
You can also redimension the array within the loop, or later on, to hold a different number of items, but if you want to keep the items already stored in the array you must use ReDim:
ReDim Preserve DynArray(i)
It's also good practice in general to declare the array type. When you use Dim DynArray() this creates an array of type Variant which can hold anything (String, Double, Object, etc.). If you explicitly declare the type e.g. Dim DynArray() as Integer then it'll only allocate enough memory to hold integers, which is more efficient. For many applications the difference in speed will not make a difference, but when you're dealing with looping through something thousands of times it can matter.