Excel v.16 VBA SeleniumBasic array.length equivalent in Selenium - arrays

I have an array, and it used to work just fine in VBA. I am now using SeleniumBasic and am trying to find the equivalent of the command ".length"
Dim i As Object
Dim elmCollection As Object
Set elmCollection = WDrv.FindElementsByTag("table")
For i = 0 To (elmCollection.Length)
It bombs out on the "For" statement. So, is there an equivalent to the ".length" in SeleniumBasic?

In visual basic it's ubound(array) to get the upper boundary of an array.
You'll want to use:
For i = 0 To ubound(elmCollection)

Selenium basic WebElements collections IIRC start at 1 and the appropriate property is .Count. You are not working with an array.
Therefore your loop should in fact be a For Each, e.g.
Dim i As Object: For Each i In elmCollection
to enumerate through the WebElements collection; if using the slower method of enumeration with objects then you want For i = 1 to elmCollection.Count

Related

For control variable already in use compile error

I am trying to write a nested for loop in visual basic macro which runs on excel.
Here is my simplified code
Dim intVar(2) As Integer
For intVar(1) = 0 To 4
For intVar(2) = intVar(1) To 4
Var = Var + intVar(1) + intVar(2)
Next intVar(2)
Next intVar(1)
When I try to compile the code "For control variable already in use" compile error is thrown. Is there any solution for using array variables for For Loop or should I declare different variables for each For Loop?
There are some questions with the same tag but none of them for the array type control variables. If you help me I would be glad.
Thank you for your interest

Is there a way to make an empty array and growing it as it gets data in vb.net?

I have been working on a project, and am attempting to make a new array for data. I have tried making an empty array with Dim Name() As String = {}. I am using a ListView, and the way I have done it there are blank spots where I have gotten rid of data. This is my current code:
Sub English(ByVal Country() As String, ByVal Language() As String)
rbDisplayallData.Checked = False
lstResults.Visible = True
lstResults.Items.Clear()
lstResults.Columns.Clear()
With lstResults
.View = View.Details
.Columns.Add("English Speaking Countries", 200, HorizontalAlignment.Left)
End With
For i = 0 To 181
Dim EnglishSpeakingCountries(i) As String
If Language(i) = "English" Then
EnglishSpeakingCountries(i) = Country(i)
End If
lstResults.Items.Add(New ListViewItem({EnglishSpeakingCountries(i)}))
Next
End Sub
I am trying to get rid of these spaces.
I Was thinking if I were to compact the array or make a new one with the same data going into a new array it would fix the issue.
If you have a solution please let me know.
There are two things that could be considered an empty array
An array with no elements, i.e. a Length of zero.
An array where every element is Nothing.
All arrays are fixed-length. Once you create an array with a particular number of elements, it always has that number of elements. You can use ReDim Preserve or Array.Resize but, in both those cases, what actually happens is that a new array is created and the elements copied from the old array. The new array is assigned to the same variable but anywhere the old array is referenced, it will still have that same number of elements. Try running this code to see that in action:
Dim a1 As String() = {}
Dim a2 As String() = {"First", "Second", "Third"}
Dim b1 = a1
Dim b2 = a2
Console.WriteLine(a1.Length)
Console.WriteLine(a2.Length)
Console.WriteLine(b1.Length)
Console.WriteLine(b2.Length)
Console.WriteLine()
ReDim Preserve a1(2)
Array.Resize(a2, 6)
Console.WriteLine(a1.Length)
Console.WriteLine(a2.Length)
Console.WriteLine(b1.Length)
Console.WriteLine(b2.Length)
Console.ReadLine()
Output:
0
3
0
3
3
6
0
3
As you'll be able to see, a1 and a2 end up referring to new arrays with the specified lengths but the original arrays with the original lengths still exist and are still accessible via b1 and b2.
If you start with an array with no elements then you can use ReDim Preserve or Array.Resize to give the appearance of resizing the array but that's not really what's happening and that should generally be avoided. If you know how many elements you'll end up with then you could create an array of that size and then set each element in turn. You'd need to keep track of the next element index though, so that's still a bit tedious.
Generally speaking, if you want an array-like data structure but you want it to be able to grow and shrink as required, you should use a collection. The most common collection is the List(Of T), where T is any type you care to specify in your code. If you want to store String objects then use a List(Of String). You can call Add to append a new item to the end of the list, as well as Insert, Remove and RemoveAt methods. You can also get or set an item by index, just as you can do for array elements.
Note that a List(Of T) actually uses an array internally and uses the aforementioned method of "resizing" that array. It optimises the process somewhat though, which makes the code easier for you to write and large collections more efficient to use.
It's worth noting that, in your own code, the Columns and Items properties of your ListView are both collections, although they are slightly different to the List(Of T) class.
Looking at your original code, this:
For i = 0 To 181
Dim EnglishSpeakingCountries(i) As String
If Language(i) = "English" Then
EnglishSpeakingCountries(i) = Country(i)
End If
lstResults.Items.Add(New ListViewItem({EnglishSpeakingCountries(i)}))
Next
could be changed to this:
Dim englishSpeakingCountries As New List(Of String)
For i = 0 To 181
If Language(i) = "English" Then
englishSpeakingCountries.Add(Country(i))
lstResults.Items.Add(Countries(i))
End If
Next
Note that you're just adding items to two collections. I guess the question is whether you actually need this extra collection at all. If you do want to use it later then you need to assign it to a member variable rather than a local variable. If you don't need it later then don't create it at all. As I said, you're already adding items to a collection in the ListView. Maybe that's all you need, but you haven't provided enough info for us to know.

How to obtain 2 dimensional arrays of Single in VB.NET exactly like in VBA?

I have some code written in VBA that uses a function of the particular environment I programmed in, which given some empty, not fixed-dimensional Single arrays, gives them back 2 dimensional and filled with data. It also produces a Variant as output.
The VBA code is:
Dim vDummy As Variant
Dim RealLev1() As Single, ImagLev1() As Single
vDummy = FFPOL1Array(RealLev1, ImagLev1)
Now, I know for sure that FFPOL1Arrayis a routine written in FORTRAN, but I cannot access to its code by any means.
I successfully managed to address the same routine in a VB.NET piece of code by writing a workaround that "links" my code to the environment mentioned above and uses its own scripting routines.
My VB.NET code would be:
Dim vDummy As Object
Dim RealLev1(,) As Single, ImagLev1(,) As Single
vDummy = NSI.FFPOL1Array(RealLev1, ImagLev1)
NSI is the "scripting routines object", which is working with many other functions and subroutines.
Sadly the code above does not work because (according to the debugger) of a type conflict. So I checked the Classes-Explorer and found out that the FFPol1Array class is defined as:
get_FFPOL1Array(ByRef System.Array, ByRef System.Array) As Object
set_FFPOL1Array(ByRef System.Array, ByRef System.Array, ByRef Object)
Thus I tried to Dim my arrays as System.Array instad of Single but this failed too always because of a type conflict. What am I doing wrong?
OK this was a little ridiculous but I managed to understand that I eventually had to initialize the Arrays, because the FORTRAN function did not do that:
Dim RealLev1 As Array = Array.CreateInstance(GetType(Single), 1, 1)
Dim ImagLev1 As Array = Array.CreateInstance(GetType(Single), 1, 1)
This did the job. Even better was:
Dim RealLev1(,) As Single = Array.CreateInstance(GetType(Single), 1, 1)
Dim ImagLev1(,) As Single = Array.CreateInstance(GetType(Single), 1, 1)
As #Nathan_Sav suggested, get_FFPOL1Array is returning an Object so you need to use Set.
Set vDummy = NSI.FFPOL1Array(RealLev1, ImagLev1)

Find Array index that contains string

I have file with tags and targets, this is example:
TAG1|TARGET1,TARGET2
TAG2|TARGET3,TARGET4
I start by creating String Array using File.ReadAllLines
Dim MAIN As String() = File.ReadAllLines("")
At some point I have one of targets and I need to know what was the tag index (which array line is it), so for example if I have TARGET3 I want to know it's in second line so it's in MAIN(1) and then I can grab TAG = TAG2.
I can't get it working, I tried few methods:
Array.IndexOf(MAIN,"TARGET3")
always returned -1, it worked with full string tho,
Array.IndexOf(MAIN,"TAG2|TARGET3,TARGET4")
returned 1. I tried with Array.FindIndex, was the same.
So my question is: how to get index of partial array item. Thank you for any help.
You can use Linq to search your array in this way
Dim search = "TARGET3"
Dim line = MAIN.FirstOrDefault(Function(x) x.Contains(search))
This will return directly the line with the matching word

Populating 2D-Arrays from CSV (without m*n-Loops)

while migrating an Excel-VBA project to Visual Basic 2010, I came across a problem when populating arrays.
In Excel-VBA I would do something like
Function mtxCorrel() As Variant
mtxCorrel = wsCorr.UsedRange
End Function
to read an m*n-matrix (in this case n*n), that is conveniently stored in a worksheet, into an array for further use.
In VB2010 I obviously won't use an Excel-Worksheet as storage. csv-Files (see below) seem like a decent alternative.
I want to populate an 2d-array with the csv-contents without looping n*n-times. Let's assume I already know n=4 for demonstration purposes.
This suggests that what I want to do cant be done.
Nevertheless I still hope something like the following could work:
Function mtxCorrel() As Object
Dim array1(4, 4) As String
Using ioReader As New Microsoft.VisualBasic.FileIO.TextFieldParser("C:\cm_KoMa.csv")
With ioReader
.TextFieldType = FileIO.FieldType.Delimited
.SetDelimiters(";")
' Here I want to...
' A) ...either populate the whole 2d-array with something like
array1 = .ReadToEnd()
' B) ... or populate the array by looping its 1d-"rows"
While Not .EndOfData
array1(.LineNumber, 0)= .ReadFields()
End While
End With
End Using
return array1
End Function
Notes:
I'm mainly interested in populating the array.
I'm less interested in potential errors with determining which csv-line belongs into which 1d-"row", and also not interested in checking n.
Appendix: sample csv-File:
1;0.5;0.9;0.3
0.5;1;0.6;0.2
0.9;0.6;1;0.1
0.3;0.2;0.1;1

Resources