I am use Vb to write for loop,
i=1 to 3
j=1 to 3
how to make the i+j result become 1+1,2+2, 3+3.
I know for C#, it can be for(i=0,j=0;i<10,j<10;i++,j++)
just don't know how to write in VB
Unfortunately, as of March 2022, Microsoft seems to have finally pulled their 25+ year-old VBScript language documentation from their documentation website, however third-party content-mirrors exist with the documentation for VBScript's For Next statement
As per the VBScript documentation...
TL;DR: You can't. VBScript's For Next statement only supports updating a single variable inside.
You can still declare and manually increment your own variables in the loop though, e.g.
Using a single variable:
Option Explicit
Dim i
For i = 0 To 5 Step 1
Call DoStuff
Next
Using multiple variables requires separate Dim declarations and incrementing them inside the For loop body:
Option Explicit
Dim i, j, k
Let j = 0
Let k = 0
For i = 0 To 5 Step 1
Call DoStuff
Let j = j + 1
Let k = k + 1
Next
Dim result As Integer
For i = 1 To 3
For j = i To i
result = i + j
Console.WriteLine(i.ToString + "+" + j.ToString + "=" + result.ToString)
Next
Next
Or you can also write
Dim i, j, result As Integer
i = 0
j = 0
While i < 10 And j < 10
result = i + j
Console.WriteLine(i.ToString + "+" + j.ToString + "=" + result.ToString)
i += 1
j += 1
End While
If you want to achieve the effect you said, I generally like to use two for loops, and I don't like to use while loops (personal preference).
Related
I have three arrays, DueDateArr, MilestoneDollarsArr, MilestoneNameArr.
I wish to sort DueDateArr chronologically and using the same sorting procedure also sort the other arrays in the same order. I used How can I sort dates in an array in vba? with additional array sorting parts but this doesn't seem to work correctly. In the output everything is ok except for the first entry being the wrong date.
Alternatively if its possible I'd like to use something like a linked list that they have in java that is a sortable multiple dimensional array with different variable types.
Data is as follows:
Sorted data is as follows: (note first entry is incorrect)
Dim TotalCountMinusOneForArrays as Integer
Dim DueDateArr() As Date
Dim MilestoneDollarsArr() As Double
Dim MilestoneNameArr() As String
Dim DueDateValue As Date
Dim MilestoneNameValue As String
Dim DueDateInfo As Date
Dim MilestoneDollarsInfo As Double
Dim MilestoneNameInfo As String
Dim i As Long, j As Long
i = 0
j = 0
For j = 2 To TotalCountMinusOneForArrays
DueDateInfo = DueDateArr(j)
MilestoneDollarsInfo = MilestoneDollarsArr(j)
MilestoneNameInfo = MilestoneNameArr(j)
For i = j - 1 To 1 Step -1
If (DueDateArr(i) <= DueDateInfo) Then GoTo Sort
DueDateArr(i + 1) = DueDateArr(i)
MilestoneDollarsArr(i + 1) = MilestoneDollarsArr(i)
MilestoneNameArr(i + 1) = MilestoneNameArr(i)
Next i
i = 0
Sort: DueDateArr(i + 1) = DueDateInfo
MilestoneDollarsArr(i + 1) = MilestoneDollarsInfo
MilestoneNameArr(i + 1) = MilestoneNameInfo
Next j
The simple approach would be to programmatically sort your data first using built-in sort functionality and then populate the array. However, when that is not an option, the two popular solutions are Bubble Sort or Merge Sort
Bubble sort being the easiest to apply:
Do Until bSort = False
bSort = False
For i = 0 to UBound(ArrToSort) - 1
If ArrToSort(i + 1) < ArrToSort(i) Then
tempVal = ArrToSort(i)
ArrToSort(i) = ArrToSort(i + 1)
ArrToSort(i + 1) = tempVal
bSort = True
End If
Next i
Loop
For your case, if you wanted to do it multidimensionally instead of with several arrays you could do this
Do Until bSort = False
bSort = False
For i = 0 to UBound(ArrToSort) - 1
If CDate(ArrToSort(i + 1, 1)) < CDate(ArrToSort(i, 1)) Then
for i2 = 1 to 3
tempVal(1, i2) = ArrToSort(i, i2)
ArrToSort(i, i2) = ArrToSort(i + 1, i2)
ArrToSort(i + 1) = tempVal(1, i2)
next i2
bSort = True
End If
Next i
Loop
Where ArrToSort(i, 1) is your date data in your multidimensional array.
EDIT:
Worth mentioning, to my knowledge there sadly is no fast way to sort arrays in excel VBA other than the methods provided.
EDIT 2:
Added CDate() around the date values of the array in the Bubble Sort.
I am new with VBA and trying to do a trinomial option pricing tree with parameters from -n to n defined. How can I rewrite my VBA function with a double loop to provide all output as it seems to only show the value of S. In the end I want to sum all values and discount them but I cannot get past my double loop providing only one output. If I put the MsgBox between k and i loop it returns nothing. Please can someone assist getting this to work as I don't have the hang of VBA yet.
Public Function LoopTest(S As Double, u As Double, n As Integer)
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim St() As Double
ReDim St(2 * n + 1)
For k = 0 To n Step 1
For i = -k To k Step 1
St(i, k) = S * u ^ i
Debug.Print St(i, k)
MsgBox ("DebugToPrint")
' Payoff(i,k) = Application.WorksheetFunction.Max((St(i,k) - 20), 0)
Next i
Next k
' For i from n to 2 step -1
' For j from 1 to n - 2
' Payoff(i - 1, j) = Payoff(i, j) + Payoff(i, j + 1) + Payoff(i, j + 2)
' Next i
' Next k
LoopTest = St()
End Function
How do I get output
k=0 St = S*u^0
k=1 St = S*u^-1 , St = S*u^0 , St = S*u^1
k=2 St = S*u^-2 , St = S*u^-1 , St = S*u^0 , St = S*u^1 , St = S*u^2
etc and then sum everything afterwards as output?
I'm not totally following the example but from the description it sounds like you're interested in a recursive process. It can be tricky and will leave you in an endless loop if you're not careful. Does this previous post help you? VBA recursive "For loops" Permutation?
I am working a code, and I have a problem with Excel's XIRR function.
You have a matrix with 2 columns (dates and amounts), so the inputs are the matrix, a date, and a quantity. Inside the code it takes the values below the date you used as input, makes a new array with those values, and add also the date and amount you entered as inputs. And the output should be the XIRR of that array. It doesn´t seem to work. It works with IRR, with dates are an important input. Does someone know how to fix this problem? Thanks in advance!
Function Retorno(matriz As Range, dia As Date, valuacion As Double) As Double
Dim Datos As Range
Dim Aux1()
Dim Aux2()
Dim i, j, m, n As Integer
Set Datos = matriz
j = 0
For i = 1 To Datos.Rows.Count
If Datos(i, 1) <= dia Then
j = j + 1
End If
Next i
ReDim Aux1(1 To j + 1)
ReDim Aux2(1 To j + 1)
For n = 1 To j + 1
Aux1(n) = Datos(n, 2)
Next n
Aux1(j + 1) = valuacion
For m = 1 To j + 1
Aux2(m) = Datos(m, 1)
Next m
Aux2(j + 1) = dia
Retorno = WorksheetFunction.Xirr(Aux1, Aux2)
End Function
Your last Aux2(j + 1) = dia is overwriting the second date in the array with the first date, giving you two identical dates in the date array.
Possibly you want to delete that line.
The other possible answer to this problem is to convert the date to numbers if you do this: Aux2(m) = Datos(m, 1)*1 XIRR will work too.
I have a set which has an unknown number of objects. I want to associate a label to each one of these objects. Instead of labeling each object with a number I want to label them with letters.
For example the first object would be labeled A the second B and so on.
When I get to Z, the next object would be labeled AA
AZ? then BA, BB, BC.
ZZ? then AAA, AAB, AAC and so on.
I'm working using Mapbasic (similar to VBA), but I can't seem to wrap my head around a dynamic solution. My solution assumes that there will be a max number of objects that the set may or may not exceed.
label = pos1 & pos2
Once pos2 reaches ASCII "Z" then pos1 will be "A" and pos2 will be "A". However, if there is another object after "ZZ" this will fail.
How do I overcome this static solution?
Basically what I needed was a Base 26 Counter. The function takes a parameter like "A" or "AAA" and determines the next letter in the sequence.
Function IncrementAlpha(ByVal alpha As String) As String
Dim N As Integer
Dim num As Integer
Dim str As String
Do While Len(alpha)
num = num * 26 + (Asc(alpha) - Asc("A") + 1)
alpha = Mid$(alpha, 2,1)
Loop
N = num + 1
Do While N > 0
str = Chr$(Asc("A") + (N - 1) Mod 26) & str
N = (N - 1) \ 26
Loop
IncrementAlpha = str
End Function
If we need to convert numbers to a "letter format" where:
1 = A
26 = Z
27 = AA
702 = ZZ
703 = AAA etc
...and it needs to be in Excel VBA, then we're in luck. Excel's columns are "numbered" the same way!
Function numToLetters(num As Integer) As String
numToLetters = Split(Cells(1, num).Address(, 0), "$")(0)
End Function
Pass this function a number between 1 and 16384 and it will return a string between A and XFD.
Edit:
I guess I misread; you're not using Excel. If you're using VBA you should still be able to do this will the help of an reference to an Excel Object Library.
This should get you going in terms of the logic. Haven't tested it completely, but you should be able to work from here.
Public Function GenerateLabel(ByVal Number As Long) As String
Const TOKENS As String = "ZABCDEFGHIJKLMNOPQRSTUVWXY"
Dim i As Long
Dim j As Long
Dim Prev As String
j = 1
Prev = ""
Do While Number > 0
i = (Number Mod 26) + 1
GenerateLabel = Prev & Mid(TOKENS, i, 1)
Number = Number - 26
If j > 0 Then Prev = Mid(TOKENS, j + 1, 1)
j = j + Abs(Number Mod 26 = 0)
Loop
End Function
Please help , this is my first try to code something useful by VBA and I am self-learning now. And I got that above error . Please help
Sub Bezier()
Dim C As Double, k As Integer, ansx As Double, ansy As Double, t As Double, n As Integer
n = 3
For i = 0 To 100
t = i * 0.01
ansx = 0
ansy = 0
For k = 0 To n
C = (WorksheetFunction.Fact(n) / WorksheetFunction.Fact(k)) / WorksheetFunction.Fact(n - k)
ansx = ansx + Cells(k + 2, 1).Value * C * WorksheetFunction.Power(t, k) * WorksheetFunction.Power(1 - t, n - k)
ansy = ansy + Cells(k + 2, 2).Value * C * WorksheetFunction.Power(t, k) * WorksheetFunction.Power(1 - t, n - k)
Next
Cells(i + 2, 6).Value = ansx
Cells(i + 2, 7).Value = ansy
Next
End Sub
First of all, you should know, that some of functions, used on the worksheet, have limitations. So my point is avoid of using them in VBA, if it is not necessary.
For example, function POWER() returns error on attempt to raise a zero to zero. An alternative is to use 0 ^ 0 combination, which is exactly doing the same, but looks more simply and operates without such error. But also there is no embedded alternative in VBA to the FACT() function, so you can use it, or simply add your own function factor() - it's uppon your choise.
If you just have started learning VBA, I would recomend you to use Option Explicit. It will help you to find out, which variables are not defined, and sometimes to avoid errors related to variable names missprint.
Here is your code, fixed and a little bit optimized:
Option Explicit' It is an option that turns on check for every used variable to be defined before execution. If this option is not defined, your code below will find undefined variables and define them when they are used. Good practice is to use this option, because it helps you, for example to prevent missprinting errors in variable names.
Sub Bezier()
Dim C as Double , t As Double
Dim k As Long, n As Long, i As Long
n = 3
For i = 0 To 100
t = i * 0.01
Cells(i + 2, 6) = 0
Cells(i + 2, 7) = 0
For k = 0 To n
C = (WorksheetFunction.Fact(n) / WorksheetFunction.Fact(k)) / WorksheetFunction.Fact(n - k)
Cells(i + 2, 6) = Cells(i + 2, 6).Value + Cells(k + 2, 1).Value * C * (t ^ k) * ((1 - t) ^ (n - k))
Cells(i + 2, 7) = Cells(i + 2, 7).Value + Cells(k + 2, 2).Value * C * (t ^ k) * ((1 - t) ^ (n - k))
Next
Next
End Sub
UPDATE
Here are some examples of factorial calculations.
Public Function fnFact(number) ' a simple cycle example of Factorial function
Dim tmp As Long ' new temporary variable to keep the "number" variable unchanged
tmp = number
fnFact = number
While tmp > 1
tmp = tmp - 1
fnFact = fnFact * tmp
Wend
End Function
Public Function fnFactR(number) ' a simple example of recursive function for Factorial calculation
If number > 0 Then
fnFactR = fnFactR(number - 1) * number ' function calls itself to continue calculations
Else
fnFactR = 1 ' function returns {1} when calculations are over
End If
End Function
Sub Factor_test() 'RUN ME TO TEST ALL THE FACTORIAL FUNCTIONS
Dim number As Long
number = 170 ' change me to find Factorial for a different value
MsgBox "Cycle Factorial:" & vbNewLine & number & "!= " & fnFact(number)
MsgBox "WorksheetFunction Factorial:" & vbNewLine & number & "!= " & WorksheetFunction.Fact(number)
MsgBox "Recursive Factorial:" & vbNewLine & number & "!= " & fnFactR(number)
End Sub
All those functions are available to calculate Factorial only for numbers before 170 inclusively, because of large result value.
So for my PC the limitation for WorksheetFunction.Fact() function is also 170.
Let me know, if your PC has different limitation for this function, - it's quite interesting thing. :)
UPDATE2
It is recomended to use Long data type instead of Integer each type when integer (or whole number) variable is needed. Long is slightly faster, it has much wider limitations and costs no additional memory. Here are proof links:
1. MSDN:The Integer, Long, and Byte Data Types
2. ozgrid.com:Long Vs Integer
3. pcreview.co.uk:VBA code optimization - why using long instead of integer?
Thanks for #Ioannis and #chris neilsen for the information about Long data type and proof links!
Good luck in your further VBA actions!
I can't find a pow method on the WorksheetFunction object. There is a Power method though. Perhaps you meant that?