For loop to print control characters - vba

Alright, so I am editing a Macro for Reflection Workspace Terminal Emulator. I have a macro (it is long and not necessarily relevant, I can post the full code if anyone wants, it is about a page)
At the very end of the macro, a "Good Morning" Message is printed, and then also the value of a string variable named myName. This works fine.
What I want to do is then use a For loop to print a number of control characters (tab) equal to the amount printed in the Good Morning User. Here is the code I have so far:
Dim X As Integer
For i = 1 To i = (13 + Len(myName)) 'Good Morning + a space character will always = 13
ibmCurrentScreen.SendKeys (ControlKeyCode_Tab)
Next i
End Sub
I would use the Chr() function to print the control characters, but it seems that this particular program uses ControlKeyCode_X to print them.

The For...Next loop in VBA is a simple single variable counter based loop and cannot have complex criteria or multiple counters like in some other languages (e.g. in C# for(int i = 0, int j = 10; i < 10; i++, j--)). In VBA, therefore, the i = after To is redundant because it cannot be anything other than i.
The 'For' loop in VBA therefore only specifies the counter once. It should be:
For i = startVal To endVal [step incrementVal]
...
Next [i]
i = variable to vary
startVal = start value
endVal = end value (inclusive, i.e. To 10 will include 10 as the final value)
incrementVal = optional value to increment/decrement by each loop
(default = 1)
The counter is always incremented/decremented at the end of each loop then evaluated against endVal (i.e. for a vanilla increment by one loop, after exiting the loop it will be endValue + 1).
Note (unrelated to your situation) that you can change the value of i in the loop, e.g. to increment twice because of some special circumstance.
Specifying the variable with the Next statement is optional and has no effect on behaviour (any nested loop must always be closed before an outer loop) but is good practice for reference when you have many For...Next loops so it is clear which loop the Next is closing (although you should be religiously indenting or otherwise delineating your code)
So in your case For i = 1 To (13 + Len(myName)) instead.

Related

Remove elements in an arraylist that exist in another arraylist

i have 2 array list, dateListDead and dateListNotMinggu. Both is DateTime List of Array. This is the ilustration of the date value in list of array
The arrayList value
its supposed to remove specific element that exist in other array list.
so far i tried, this code it's not working.
Dim d, x As Integer
For x = 0 To dateListDead.Count - 1
For d = 0 To dateListNotMinggu.Count - 1
If dateListNotMinggu(d) = dateListDead(x) Then
dateListNotMinggu.RemoveAt(d)
End If
Next
Next
the error is : index out of range. how could it be ? i define the parameter of end looping base on arraylist.count -1
The main is that you are using a For loop from the first index to the last index but you don't account for the change of index when you remove a value. If there might be multiple values then you should start and the end rather than the beginning. In that case, removing an item won't affect the indexes of the items you are yet to test. If there can only be one match then you should be exiting the loop when you find one.
Either way, while you don't have to, I would suggest using a For Each loop on the outside. If you want to perform an action for each item in a list then that's exactly what a For Each loop is for. Only use a For loop if you need to use the loop counter for something other than accessing each item in turn.
For multiple matches:
For Each dateDead As Date In dateListDead
For i = dateListNotMinggu.Count - 1 To 0 Step -1
If CDate(dateListNotMinggu(i)) = dateDead Then
dateListNotMinggu.RemoveAt(i)
End If
Next
Next
For a single match:
For Each dateDead As Date In dateListDead
For i = 0 To dateListNotMinggu.Count - 1
If CDate(dateListNotMinggu(i)) = dateDead Then
dateListNotMinggu.RemoveAt(i)
Exit For
End If
Next
Next
Note that I have also cast the Date values as that type for comparison, which is required with Option Strict On. Option Strict is Off by default but you should always turn it On because it will help you write better code by focusing on data types.
Also, the code above would work with a List(Of Date) as well as an ArrayList but the casts would not be required with a List(Of Date). That's one of the advantages of using a generic List(Of T) over an ArrayList, which paces no restrictions on what it can contain.
If you really must use a For loop because that's what your homework assignment says then it would look like this:
For i = 0 To dateListDead.Count - 1
For j = dateListNotMinggu.Count - 1 To 0 Step -1
If CDate(dateListNotMinggu(j)) = CDate(dateListDead(i)) Then
dateListNotMinggu.RemoveAt(j)
End If
Next
Next
and this:
For i = 0 To dateListDead.Count - 1
For j = 0 To dateListNotMinggu.Count - 1
If CDate(dateListNotMinggu(j)) = CDate(dateListDead(i)) Then
dateListNotMinggu.RemoveAt(j)
Exit For
End If
Next
Next
Note that it is convention to use i as a first option for a loop counter, then j for the first nested loop, then k for the second nested loop. You should only use something else if you have good reason to do so. Remember that the loop counter doesn't represent the value in the list but rather its index. That's why you use i for index and not d for date or the like.
EDIT:
As per Jimi's comment below, the way this would usually be tackled is with a simple LINQ query. If you were using LINQ then you definitely wouldn't be using an ArrayList but rather a List(Of Date). In that case, the code would look like this:
dateListNotMinggu = dateListNotMinggu.Except(dateListDead).ToList()
If you were completely insane and wanted to use LINQ and ArrayLists then this would work:
dateListNotMinggu = New ArrayList(dateListNotMinggu.Cast(Of Date)().
Except(dateListDead.Cast(Of Date)()).
ToArray())
Take note that, as I replied in the comments, using LINQ will generate a new list, rather than changing the existing one.

How to use variables in regular MS excel expressions

My research shows that I need to use Visual Basic. I am a programmer/developer, but have never used VB so if anyone could dumb it down it would be appreciated.
Here's my working excel function:
=IF(MATCH(1,E1:DP1,0),D1,FALSE)
I want to loop a few of those numbers such that:
=IF(MATCH(141,E1:DP378,0),D378,FALSE)
THEN take my answers (which will be strings, because column D are all strings, the rest of the excel file are numbers)
=CONCAT
end goal: have 141 String arrays populated based on the data in my table.
I went ahead and made my first attempt at VBA like this:
Sub myFunc()
'Initialize Variables
Dim strings As Range, nums As Integer, answer() As Variant, listAnswers() As Variant
'set variables
strings = ("C1:C378")
nums = 141
i = 0
j = 0
ReDim Preserve answer(i)
ReDim Preserve listAnswers(j)
'answer() = {""}
'for each in nums
For counter = 0 To nums
ReDim Preserve listAnswers(0 To j)
'set each list of answers
listAnswers(i) = Join(answer(), "insertJSONcode")
j = j + 1
'for each in Stings
For Each cell In strings
If cell <> "" Then
ReDim Preserve answer(0 To i)
answer(i) = 'essentially this: (MATCH(2,E1:DP1,0),D1,FALSE)
i = i + 1
end If
next cell 'end embedded forEach
Next LCounter 'end for loop
'is this possible? or wrong syntax?
Range("A:A").Value = listAnswers() ' should print 141 arrays from A1 to A141
End Sub
EDIT:
Important note I do NOT need to call the sheet by Name. I've successfully written integer values to by excel sheet in column A without doing so.
Also, the VBA I wrote I was never intended to work, I know it's broken at least where answer(i) is supposed to write to something. I'm only putting that code there to show I was able to at least able to get into spitting distance of the proper logic and prove I've put some serious effort into solving the problem and give a rough starting point.
Here's an image of the excel format. Column C goes down to 378 and the numbers listed from E through DP are populated by a database. It consists of blank cells and numbers between 1 and 141.
Looking back at my if statement:
=IF(MATCH(2,E2:DP2,0),D2,FALSE)
If I were to type that exactly into cell B2 it would output the correct answer "text2". which is neat and all, but I need every instance of text 2 written out, then CONCAT those results. Easy so far, I could drag that down all the way through column B and have all of my "text" strings in one column, CONCAT that column and there's the answer. However I don't just need #2, I need each number between 1 and 141. Plus I want to avoid writing 141 columns with a CONCAT on top of each one.

Are if statements considered as an Iteration

Hello I'm just wondering whether an 'if' statement can be considered as an Iteration. Because Iteration is used until a certain criteria is meet to allow the code to continue.
An iteration is one cycle (one time through) a loop. If blocks are not loops.
For blocks or While blocks are loops, and executing one cycle of the contents of one of those blocks — what's inside the For block or the While block — is one iteration of the loop. If the entirety of a For block or While block is a conditional If block, then the If block could be one iteration... but not because it's an If block, but because it's what's inside the loop.
No, an iteration is a repetition of some code. Once doesn't count as a repetition, else all code would be considered an iteration.
The If statement by itself cannot be considered iteration. You can run a code block containing an if statement as many times as you wish, but this doesn't make the if statement an iterator by itself. It's what calls that code block which could stand for iteration.
If statement has some similarities with those other conditional statements :
Select Case
Try Catch
Explicit iterators are the followings :
For/Next - For Each/Next
Do/Loop
While/End While
However, you have some logic that could turn the usage of an if statement as the trigger to resume or stop conditions of a loop, without the usage of direct loop statements like For or While. But that doesn't turn that if statement an iterator by itself, because the iteration is the combination of the if statement and a specific logic allowed by the programming language.
Recursion :
Private Function ResumeIncrement(ByRef Number As Int32) As Boolean
Number = Number + 1
If Number < 10 Then
Return ResumeIncrement(Number)
Else
Return False
End If
End Function
GoTo statement :
Private Sub TestGoTo()
Dim Number As Int32 = 0
IncrementMore:
Number = Number + 1
If Number < 10 Then
GoTo IncrementMore
End If
End Sub
And as stated by Joel Coehoorn above, the If block can contain anything, including iterator blocks triggered by For, While or Do. If you remove the contained block, that doesn't change anything in what the if part is supposed to do : a conditional check !
You can also do the inverse, and use an If block to control the way an iteration behaves. Like :
If SomeCondition Then
Exit For
' Or Exit While, etc. ie, using the 'Exit' statement
End If
or
i = 0
Do
i = i + 1
' ^^ capture i in Debug or Console
' Control the value of i...
If i Mod 2 = 0 Then
i = i - 2
Else
i = i * 3
End If
Loop While i < 30
' i = 1, 4, 3, 10, 9, 28, 27, [Exit Do with i = 81]
In the two examples above, the If statement is either there to break the iteration, or try again, that said, to "control the iteration", but in no means, to stand for iterator by itself.
Here is also another answer to clear out one uncertainty. You asked
Are if statements considered as an Iteration ?
(You made "if statements" plural) Then you said
Hello I'm just wondering whether an 'if' statement can be considered
as an Iteration. Because Iteration is used until a certain
criteria is meet to allow the code to continue.
(then you made it singular.. ???) That "...Iteration is used until..." should self answer your question alone, assuming you're iterating code blocks (which is the way it is understood here)
But what if you're talking about iterating some possible values until one meets your requirements..?
If MyValue = "" Then
' ...
ElseIf MyValue.StartsWith("A") Then
' ...
ElseIf MyValue.ToUpper = "TEST" Then
' ...
Else
' ...
End If
is similar to :
Select Case True
Case MyValue = "":
' ...
Case MyValue.StartsWith("A")
' blah blah blah
End Select
or
If MyValue = "" Then GoTo EmptyString
If MyValue.StartsWith("A") Then GoTo StartsWithA
If MyValue.ToUpper() = "TEST" Then GoTo IsTEST Else GoTo DoNothing
EmptyString:
' ...
GoTo DoNothing
StartsWithA:
' ...
GoTo DoNothing
IsTEST:
' ...
GoTo DoNothing
DoNothing:
' Resume...
Etc.
That's not an iteration ! That's a list of evaluation that are processed in order. When a condition evaluates to True, the related code is executed. Unlike iteration, this is just a matter of selecting the right path and resume, not walking the very same path several times (loops)
Yes, you're iterating through a collection of possible values (condition states) but NO, you're not iterating the If statement. You're only checking the result of each single If test once.

The do while loop structure

In the do while loop structure usually there's a part where you declare a variable equal to a number (in this case i) and then in a second part you make a increment (i+1). I've made this example in vba, but the structure could be repeated in several different programming languages like the for in php when you're getting data from a database. Now, what I would like to understand better is the relation between the previous mentioned declarations, that is i = some number and i = i + 1 . Wouldn't this generate a problem of interpretation since you're declaring a variable to something and then assigning a different value right after it? Is the second declaration of the variable value, i = i + 1, a new variable calling the previous one or both i's are the same? This is the general orientation I intend with this question. I think explaining the scoop of both variables would help understanding. Thanks!
Sub DoWhile()
Dim x, i, sum
x = 10
i = 1
sum = 0
Do While i < x
sum = sum + i
i = i + 1
Loop
MsgBox “Sum = ” & sum
End Sub
A variable is really just a location in memory. That location can have any value. By setting i=i+1, you're really saying "take the value at position i, add 1 to it, and store it at position i". No new variable is created. There's no problem with the computer interpreting this- what it cares about is the location of i, which isn't changing. It still knows where to find i, regardless of how many times you change the value there.
Since you have created the variable i as a global variable, any reference or modification to i in the sub will be on the same variable. That being said:
Dim i as int
i = 1
Do while i < 11
MsgBox("The value of i is: " & i)
i = i + 1
Loop
would display 10 messageboxes showing the value of i being between 1 and 10.
When the program encounters i = i + 1, the computer 'sees' this as take the value of i, add one to it, and store the result in the variable i.
Hope that helps.

Nested loop with same variable

Is that possible for me to do nested loop in VB with same counter
The code is somehow like this
For a As Integer = 1 to Console.ReadLine
For a = 1 to a
Console.WriteLine("*")
Next
Console.WriteLine()
Next
The program is designed for drawing a triangle of * with just a single variable at all
VB just disallow me to use a in nested loop again
Error: ...Variable 'a' is alreay used by a independent loop.
I have my own usage, can only use 1 variable.
What changing the second FOR loop to a WHILE loop?
For a As Integer = 1 to Console.ReadLine
Do While a <=5
Console.WriteLine("Line: " & a)
Exit Do
Loop
Next
Here's a different idea. You may consider splitting your integer variable into 2 parts 16-bit parts, keep user's input in the upper 16-bits, and current iteration value in the lower 16-bits (you'll need to use WHILE instead of FOR).
In fact, what you need is to start your inner counter by the value of a, if I've understand. And what you are doing is create another loop inside starting by 1.
For a As Integer = 1 to Console.ReadLine
For b As Integer = a to 5
Console.WriteLine("Line: " & a)
Next
Next
You cannot declare another variable with the same name in the same scope. But the inner loop is in the same scope as the outer loop. That's why you get that compiler error.
You can use a different name:
Dim i As Int32
If Int32.TryParse(Console.ReadLine, i) AndAlso i > 0 Then
For a As Integer = 1 To i
For aa = 1 To i
Console.WriteLine("Line: {0} {1}", a, aa)
Next
Next
End If
To draw a triangle, as you describe, you need two variables, like this:
For a As Integer = 1 to Console.ReadLine
For b As Integer = 1 to a
Console.Write("*")
Next
Console.WriteLine()
Next
If you used the same variable in the inner loop, the inner loop would change the value of the variable, which in most cases would not be what you want, and in all cases would be incredibly confusing. For that reason, VB forces you to use a different iterator in each nested For loop.