Visual Basic Fill Array with simple number set - vba

I need to fill an array with numbers 1-50, and I currently have the code:
Dim numberSet(49)
For x = 1 To 50
numberSet(x - 1) = x
Next x
The challenge is to do it in the least amount of lines possible. This part is bugging me because it seems like i shouldn't be using 4 lines for something so basic.
Any thoughts from you guys? I want to avoid doing something like = {1,2,3,4,5...50} if I can. Thanks!

In one line:
Dim numberSet(49): For x = 1 To 50: numberSet(x - 1) = x: Next x

One line (but it creates a 1-based array...)
Sub TT()
Dim arr
arr = Application.Transpose([=ROW(A1:A50)])
Debug.Print UBound(arr)
Debug.Print arr(1)
Debug.Print arr(13)
End Sub
...and if you turn off Option Explicit you can skip the declaration. But don't do that ;-)

Related

Excel VBA - For Loop with specific values

I'm trying to create a For Loop that only selects some values but can't work out the Syntax, or if it's even possible?
I want it to be like
Dim i As Integer
For i = 1,3,8,15 Then
Do something
Next i
Any Ideas?
Try
Sub Demo()
Dim indexArr As Variant
Dim i As Long
indexArr = Array(1, 3, 8, 15)
For i = LBound(indexArr) To UBound(indexArr)
Debug.Print indexArr(i)
Next i
End Sub
You can do following:
Dim i as Variant
Dim iArray as Variant
iArray=Array(1,3,8,15)
For Each i In iArray
'Do Something
Next i
Cheers
You can't.
If there is a pattern you can use Step
For i = 1 to 15 Step 2
Which will do 1,3,5,7,...
In this case since there is no pattern you will need to add an If or Select Case:
Dim i As Integer
For i = 1 to 15 Then
Select Case i
Case 1,3,8,15
'Do Something
End Select
Next i
You can use if statement:
Dim i As Integer
For i = 1 To 15 Then
If i = 1 or i = 3 or i = 8 or i = 15 Then
'Do something
End If
Next i
Hope this help.
This solution combines elements from the array solution above with the ease of use that I inferred was wanted by the OP. The array method requires looping through the array elements and then converting the array element back into a variable. This method skips 2 bits. Firstly, it skips the complex step logic of stepping through array elements. Secondly, it skips the step of converting an array element back into a usable variable.
Dim number_list as collection
set number_list = new collection
number_list.add 1
number_list.add 3
number_list.add 8
number_list.add 15
for each number in number_list
'Do something with number
Next number
This is even a simplification of the routine of Kedimir:
Original question:
Dim i As Integer
For i = 1,3,8,15 Then
' Do something
Next i
Solution:
Dim i As Variant
For Each i In Array(1, 3, 8, 15)
' Do something
Next i
For your information: the Variant is needed for the For Each loop, don't try to modify it into an integer, or the For Each loop won't be accepted.
I don't think that a more resembling solution is possible :-)

Looping to find letters in a column on VBA

My macro is to send emails for some clients. It sends the email only if there is a X at one of the lines of the column B, so then it sends the whole line to the client by creating a new sheet that goes attached to the client on the email.
The problem is that I need to create a loop to count all the columns that contain the letter X, because this macro is counting only the first line that contains the letter X and then the other ones don't go to the new sheet and consequently it doesn't go to the client. Everything is OK in my macro, despite of the counter. When i run it, just the first line that contains the X goes to the client, and the others don't. Can you guys help me?
Code:
LinhaInicio = 1
While Workbooks(planilha).Sheets("Boletas").Cells(LinhaInicio, 2) <> "X"
LinhaInicio = LinhaInicio + 1
Wend
LinhaFim = LinhaInicio
While Workbooks(planilha).Sheets("Boletas").Cells(LinhaFim, 2) = "X"
LinhaFim = LinhaFim + 1
Wend
LinhaFim = LinhaFim - 1
RangeInicio = Workbooks(planilha).Sheets("Boletas").Cells(LinhaInicio, 26).Address
RangeFim = Workbooks(planilha).Sheets("Boletas").Cells(LinhaFim, 34).Address
Set RangeCopiar = ActiveSheet.Range(RangeInicio, RangeFim)
Maybe Try something like this:
Dim vArr As Variant
Dim LinhaFim As Long
Sub mainLoop()
'put all values into variant array vArr
vArr = Workbooks(planilha).Sheets("Boletas").UsedRange
For i = LBound(vArr) To UBound(vArr)
If vArr(i, 2) = "X" Then
Nestedloops (i) 'initiate nested loops
i = LinhaFim 'artificially increment counter
End If
Next i
End Sub
Sub Nestedloops(LinhaIncio As Long)
With Workbooks(planilha).Sheets("Boletas")
LinhaFim = linhaInicio
While vArr(LinhaFim, 2) = "X"
LinhaFim = LinhaFim + 1
Wend
LinhaFim = LinhaFim - 1
RangeInicio = .Cells(LinhaInicio, 26).Address
RangeFim = .Cells(LinhaFim, 34).Address
Set RangeCopiar = ActiveSheet.Range(RangeInicio, RangeFim)
'email code goes here
End With
End Sub
Tim could come up with something better though might want to see what he comes up with
you wanna search the X letter to columns or rows, sorry I didn't understand what you try to say. You want to create a loop to count all the X letter for every row and column or only for every row from a column?
here is how you define an array:
Dim timelinessSheet, o As Variant
timelinessSheet = Worksheets("your_sheet_name").Range("A2:X" & Worksheets("your_sheet_name").Cells(Worksheets("your_sheet_name").Rows.Count, "B").End(xlUp).Row).Value
and then your code
dim i as long
for i=2 to ubound (timelinessSheet,1)
if timelinessSheet(i,2)= X then
Your_condition
end if
next I

Excel VBA - Nested loop to format excel table columns

I have a macro that so far, adds 4 new table columns to an existing table ("Table1"). Now, I would like the macro to format the 3rd and 4th row as percentage. I would like to include this in the loop already listed in my code. I have tried several different ways to do this. I don't think I quite understand how the UBound function works, but hopefully you can understand what I am trying to do.
I also am unsure if I am allowed to continue to utilize the WITH statement in my nested For loop in regards to me 'lst' variable.
#Jeeped - I'm looking at you for this one again...thanks for basically walking me through this whole project lol
Sub attStatPivInsertTableColumns_2()
Dim lst As ListObject
Dim currentSht As Worksheet
Dim colNames As Variant, r1c1s As Variant
Dim h As Integer, i As Integer
Set currentSht = ActiveWorkbook.Sheets("Sheet1")
Set lst = ActiveSheet.ListObjects("Table1")
colNames = Array("AHT", "Target AHT", "Transfers", "Target Transfers")
r1c1s = Array("=([#[Inbound Talk Time (Seconds)]]+[#[Inbound Hold Time (Seconds)]]+[#[Inbound Wrap Time (Seconds)]])/[#[Calls Handled]]", "=350", "=[#[Call Transfers and/or Conferences]]/[#[Calls Handled]]", "=0.15")
With lst
For h = LBound(colNames) To UBound(r1c1s)
.ListColumns.Add
.ListColumns(.ListColumns.Count).Name = colNames(h)
.ListColumns(.ListColumns.Count).DataBodyRange.FormulaR1C1 = r1c1s(h)
If UBound(colNames(h)) = 2 or UBound(colNames(h)) = 3 Then
For i = UBound(colNames(h), 2) To UBound(colNames(h), 3)
.ListColumns(.ListColumns.Count).NumberFormat = "0%"
End if
Next i
Next h
End With
End Sub
You don't need to nest a second for loop. If you want to set the 3rd and 4th columns to a percentage, you only need to set that when the iteration of the loop (h) is 2 or 3 (remembering that arrays index from 0). You also shouldn't cross arrays for the main loop, and since LBound is in most cases 0 you might as well just use that anyway. Try this:
With lst
For h = 0 To UBound(r1c1s)
.ListColumns.Add
.ListColumns(.ListColumns.Count).Name = colNames(h)
.ListColumns(.ListColumns.Count).DataBodyRange.FormulaR1C1 = r1c1s(h)
If h = 2 or h = 3 Then
.ListColumns(.ListColumns.Count).NumberFormat = "0%"
End if
Next h
End With
To answer the other point in your question, UBound(array) just gives the index of the largest element (the Upper BOUNDary) in the given array. So where you have 50 elements in such an array, UBound(array) will return 49 (zero based as mentioned before). LBound just gives the other end of the array (the Lower BOUNDary), which is generally zero.

Why is "Rank_Eq" breaking my loop?

I have a procedure which involves ranking values. My code (stripped down to important parts) looks like this:
Dim myArray() as variant
ReDim myArray(1 to 4, 1 to x)
for i = 1 to x
myArray(1,i) = a
myArray(2,i) = b
myArray(3,i) = c
next i
for j = 1 to x
myArray(4,j) = Application.Rank_Eq(myArray(3,j), Application.Index(myArray,3,0), 1)
next j
for k = 1 to x
myFunction(myArray(4,k))
next k
Debugging it, the for j = 1 to x loop works fine if I just return, say, the value of j or the value of myArray(3,j) but it breaks out of the loop at j=1 when I use the Application.Rank_Eq() formula.
Have I done something really stupid that I just can't see, or is this an Excel issue?
EDIT:
I tried using the following to debug:
myIndex = Application.Index(myArray,3,0)
for k = 1 to x
MsgBox myIndex(k,1)
a = Application.Rank_Eq(myIndex(1,k), editedRows, 1)
next k
This appears to run ok - i.e. each value of myIndex(k,1) is returned. However, if I add MsgBox a before next k, then it breaks. This suggests it's something to do with the value being returned by Rank_Eq, no?
Not sure it's part of the issue - but I had to access the Rank_Eq method through the WorksheetFunction object, not the Application object.
Secondly, you'll notice that this function needs a Double and a Range for the first 2 arguments. Currently you are supplying a Variant and whatever the value is from your Index() method.
Try casting the Variant to a Double like so for the first argument:
CDbl(myArray(3, j))
For the second argument, I have no idea from your question how the array gets populated so I can't guess where the Range argument needs to refer to...

Variables in VBA loops

I'm trying to run a VBA application using a loop and using variables whose names depends on where in the loop I am. Specifically something like
Dim i As Integer
i = 1
Dim varname() As String
while i < 50
varname(i) = asdasd
i = i + 1
Wend
Somehow it can't read varname(i) or whatever. It reports subscript out of range.
I have no idea what the problem is, can someone helt me perhaps?
You need to give your array a capacity first.
Sub max()
Dim i As Integer
i = 1
Dim varname() As String
ReDim varname(49) '<---- There
While i < 50
varname(i) = asdasd
i = i + 1
Wend
End Sub
This is a good resource for VBA arrays:
http://msdn.microsoft.com/en-us/library/office/aa164778(v=office.10).aspx