Populating collection with arrays - vb.net

Dim A As Collection
Set A = New Collection
Dim Arr2(15, 5)
Arr2(1,1) = 0
' ...
A.Add (Arr2)
How can I access the Arr2 through A? For example, I want to do the following:
A.Item(1) (1,1) = 15
so the above would change the first element of the first two-dimensional array inside the collection...

Hmmm...the syntax looks legal enough without having VBA in front of me. Am I right that your problem is that your code "compiles" and executes without raising an error, but that the array in the collection never changes? If so, I think that's because your A.Item(1) might be returning a copy of the array you stored in the collection. You then access and modify the chosen element just fine, but it's not having the effect you want because it's the wrong array instance.
In general VBA Collections work best when storing objects. Then they'll work like you want because they store references. They're fine for storing values, but I think they always copy them, even "big" ones like array variants, which means you can't mutate the contents of a stored array.
Consider this answer just a speculation until someone who knows the underlying COM stuff better weighs in. Um...paging Joel Spolsky?
EDIT: After trying this out in Excel VBA, I think I'm right. Putting an array variant in a collection makes a copy, and so does getting one out. So there doesn't appear to be a direct way to code up what you have actually asked for.
It looks like what you actually want is a 3-D array, but the fact that you were tyring to use a collection for the first dimension implies that you want to be able to change it's size in that dimension. VBA will only let you change the size of the last dimension of an array (see "redim preserve" in the help). You can put your 2-D arrays inside a 1-D array that you can change the size of, though:
ReDim a(5)
Dim b(2, 2)
a(2) = b
a(2)(1, 1) = 42
ReDim Preserve a(6)
Note that a is declared with ReDim, not Dim in this case.
Finally, it's quite possible that some other approach to whatever it is you're trying to do would be better. Growable, mutable 3-D arrays are complex and error-prone, to say the least.

#jtolle is correct. If you run the code below and inspect the values (Quick Watch is Shift-F9) of Arr2 and x you will see that they are different:
Dim A As Collection
Set A = New Collection
Dim Arr2(15, 5)
Arr2(1, 1) = 99
' ...
A.Add (Arr2) ' adds a copy of Arr2 to teh collection
Arr2(1, 1) = 11 ' this alters the value in Arr2, but not the copy in the collection
Dim x As Variant
x = A.Item(1)
x(1, 1) = 15 ' this does not alter Arr2

Maybe VBA makes a copy of the array when it assigns it to the collection? VB.net does not do this. After this code, a(3,3) is 20 in vba and 5 in vb.net.
Dim c As New Collection
Dim a(10, 10) As Integer
a(3, 3) = 20
c.Add(a)
c(1)(3, 3) = 5

I recently had this exact issue. I got round it by populating an array with the item array in question, making the change to this array, deleting the item array from the collection and then adding the changed array to the collection. Not pretty but it worked....and I can't find another way.

If you want the collection to have a copy of the array, and not a reference to the array, then use the array.clone method:-
Dim myCollection As New Collection
Dim myDates() as Date
Dim i As Integer
Do
i = 0
Array.Resize(myDates, 0)
Do
Array.Resize(myDates, i + 1)
myDates(i) = Now
...
i += 1
Loop
myCollection.Add(myDates.Clone)
Loop
At the end, myCollection will contain the accumulative collection of myDates().

Related

How do I insert data from a text file into a 2D Array in VB.Net?

Currently I have these data inside my textfile.txt:
I want to split them up into a 2D array when a comma is met. How do I do so?
This is my code for now. Please do point out the mistakes I made.
Dim priceArray(5, 2) As String
Dim i, j As Integer
Dim data As String
Dim oilpriceFile As System.IO.StreamReader
oilpriceFile = New System.IO.StreamReader("C:\Users\zack\OneDrive\Desktop\oilprice.txt")
For i = 0 To UBound(priceArray)
data = oilpriceFile.ReadLine()
For j = 0 To UBound(priceArray)
priceArray(i, j) = data.Split(",") //there's an error stating "value of type string() cannot be converted into string"
j = j + 1
Next
i = i + 1
Next
There are several things you are doing incorrectly.
First turn on Option Strict in the Project Properties and also under Options on the Tools menu.
You do not declare the increment variables used in For loops.
StreanReader needs to be disposed. You should know this because you always check the documentation before you use an unfamiliar framework class. When you do this you will see a Dispose method. When you see this, it needs to be called when you are through with using it. See Using...End Using.
You don't have to deal with Dispose if you use File.ReadAllLines(). This returns an array of the lines in the file.
A For loop increments the value of the first variable automatically. You do not increment it explicitly or you will skip values.
You have defined a 2 dimensional array. When you call UBound on the array, which dimension are you calling it on?? You must indicate which dimension you are asking about.
UBound(priceArray, 1) and UBound(priceArray, 2)
Where 1 and 2 designate the dimension you are getting.
This is the old vb6 way to get this value. The .net framework provides GetUpperBound() for the same purpose. This method uses the .net zero based rank where GetUpperBound(0) will return upper bound of the first dimension of the array.
The next problem is the use of Spilt. Split returns an array of strings and you are trying to assign it to a single string. It takes a Char as a parameter. You have passed a String. To tell the compiler that you intend a Char follow the String by a lower case c.
A side note. // is the comment indicator in C#. In vb.net use the single quote '.
Private Sub OPCode()
Dim priceArray(5, 2) As String
Dim lines = File.ReadAllLines("C:\Users\zack\OneDrive\Desktop\oilprice.txt")
For i = 0 To priceArray.GetUpperBound(0)
Dim data = lines(i)
Dim splits = data.Split(","c)
For j = 0 To priceArray.GetUpperBound(1)
priceArray(i, j) = splits(j)
Next
Next
End Sub

Dynamically create variables in VB.NET

I have been trying to figure this out for some time now and can't seem to figure out an answer to it. I don't see why this would be impossible. I am coding in VB.NET.
Here is my problem:
I need to dynamically create variables and be able to reference them later on in the code.
More Details:
The number of variables comes from some math run against user defined values. In this specific case I would like to just create integers, although I foresee down the road needing to be able to do this with any type of variable. It seems that my biggest problem is being able to name them in a unique way so that I would be able to reference them later on.
Simple Example:
Let's say I have a value of 10, of which I need to make variables for. I would like to run a loop to create these 10 integers. Later on in the code I will be referencing these 10 integers.
It seems simple to me, and yet I can't figure it out. Any help would be greatly appreciated. Thanks in advance.
The best way to do something like this is with the Dictionary(T) class. It is generic, so you can use it to store any type of objects. It allows you to easily store and retrieve code/value pairs. In your case, the "key" would be the variable name and the "value" would be the variable value. So for instance:
Dim variables As New Dictionary(Of String, Integer)()
variables("MyDynamicVariable") = 10 ' Set the value of the "variable"
Dim value As Integer = variables("MyDynamicVariable") ' Retrieve the value of the variable
You want to use a List
Dim Numbers As New List(Of Integer)
For i As Integer = 0 To 9
Numbers.Add(0)
Next
The idea of creating a bunch of named variables on the fly is not something you are likely to see in any VB.Net program. If you have multiple items, you just store them in a list, array, or some other type of collection.
'Dim an Array
Dim xCount as Integer
Dim myVar(xCount) as String
AddButton Event . . .
xCount += 1
myVar(xCount) = "String Value"
'You will have to keep Track of what xCount Value is equal to to use.
'Typically could be an ID in A DataTable, with a string Meaning

Array creation and population issues in visual basic

just a quick question about an issue I am having in vb.
I need to create an array, then iterate through a string, adding the string value to the array only is it does not already exist, to produce an array of unique values.
The issue I am having is with the array.length operation - on a array that is nothing I am unable to retrieve the array length (0), as such I am unable to redimensionalise the array to be array length (must be array length as arrays are indexed from 0), providing me the ability to add the new value to the array and then continue the loop until all values have been checked to see if they exist within the array (using contains) and the value contain only unique values..
Been nipping my head for hours :)
Thanks
Martin
I must assume that you are working with VB.Net, so I will answer accordingly.
The answer you are literally looking for is:
Public Function GetUniqueChars(text As String) As Char()
Dim uniqueChars() As Char
ReDim uniqueChars(0)
If String.IsNullOrEmpty(text) Then Return uniqueChars
uniqueChars(0) = text(0)
For Each c In text.Substring(1)
If Not uniqueChars.Contains(c) Then
ReDim Preserve uniqueChars(uniqueChars.Length)
uniqueChars(uniqueChars.Length - 1) = c
End If
Next
Return uniqueChars
End Function
However, starting with Net 3.5 you can use LINQ to reduce this function to one line:
uniqueChars = text.Distinct().ToArray
It's been literally years since I last programmed in VB6 (was my favorite language at one time). That being said, I recall finding the length of an array using UBound() like:
iLength = UBound(myArray)
I also remember using that number to redeclare my array to add another value (i.e. dynamic arrays) using something like:
ReDim Preserve myArray(iLength)
Perhaps that will inspire a solution for your loop.

vb.net Object(,) Array index won't find (0,0) even though it's an 11x37 array

first time questioner here. Thanks in advance for any help you can give.
I'm trying to read a bunch of data from a spreadsheet, chop it up, then throw it into a database. I would rather not do things this way, but it's a basic reality of dealing with accountant-types. Thankfully these spreadsheet reports are very consistent. Anyway, I'm using LINQ for SQL to handle the object-to-reference stuff and I'm using Microsoft.Office.Interop to get my Excel on.
I read through a directory full of .xls and for each one, I'm opening the file, getting a couple of specific data from some specific cells, and then getting a range of cells to pick out values.
Private Sub ProcessAFile(ByVal f As FileInfo)
thisFile = openApp.Workbooks.Open(f.fullName)
thisMonth = Split(thisChart.Range("D6").Value, "-").Last.Trim
thisFY = thisChart.Range("L7").Value
thisWorkArea = thisChart.Range("A14", "L51").Value2
openApp.Workbooks.Close()
...
thisWorkArea was Dimmed as a global:
Dim thisWorkArea As Object(,)
I'm getting both strings and ints in my range between A14 and L51, so making it an Object array makes sense here. I don't want to go through each row and pick out ranges in Excel, I want to just read it once and then close it.
So I'm getting the following exception:
System.IndexOutOfRangeException was unhandled
Message=Index was outside the bounds of the array.
in this function:
Private Sub fillCurrMonth()
Dim theseRows As Integer() = {0, 2, 3, 5}
For Each i In theseRows
Dim thisMonth As New Month
'make sure category is in Database
thisMonth.Dept = thisDeptName
thisMonth.FY = thisFY
thisMonth.Category = thisWorkArea(i, 0)
...
"Month" above refers to a LINQ entity. It's nothing fancy.
That last line there is where I'm catching the exception. In my watch, I find that thisWorkArea has a length of 456 and (0,0) -> "Inpatient"{String}
So why am I getting this exception? I put this in your expert hands. I'm still rather new to vb.net, so maybe I'm just missing something fundamental.
Excel uses 1-based indicies. This stems from it using VB as it's in-app programming language which traditionally used 1-based indicies.
You'll find Excel returned an array defined as thisWorkArea(1 To 11, 1 To 37) As Object
'Fix excel's 1 based index
Dim oData(UBound(xData) - 1, UBound(xData, 2) - 1) As Object
For i As Integer = 1 To UBound(xData)
For ii As Integer = 1 To UBound(xData, 2)
oData(i - 1, ii - 1) = xData(i, ii)
Next
Next

What is the C# equivalent of this Excel VBA code for Shapes?

This is the VBA code for an Excel template, which I'm trying to convert to C# in a VSTO project I'm working on. By the way, it's a VSTO add-in:
Dim addedShapes() As Variant
ReDim addedShapes(1)
addedShapes(1) = aBracket.Name
ReDim Preserve addedShapes(UBound(addedShapes) + 1)
addedShapes(UBound(addedShapes)) = "unique2"
Set tmpShape = Me.Shapes.Range(addedShapes).Group
At this point, I'm stumped by the addedShapes(), not sure what this is all about.
Update: Matti mentioned that addedShapes() represents a variant array in VBA. So now I'm wondering what the contents of addedShapes() should be. Would this be the correct way to call the Shapes.Range() call in C#?
List<string> addedShapes = new List<string>();
...
Shape tmpShape = worksheet.Shapes.get_Range
(addedShapes.Cast<object>().ToArray()).Group();
I'd appreciate anyone who's worked with VBA and C# willing to make a comment on my question & problem!
I'm not sure what your actual question is supposed to be, but addedShapes is an array. In VB and its variants, arrays are declared and accessed using () instead of [].
Also, your code looks like it's just a really long-winded way of doing:
object[] addedShapes = new object[] { aBracket.Name, "unique2" };
Shape tmpShape = worksheet.Shapes.get_Range(addedShapes).Group();
The last part might alternatively be
Shape tmpShape = worksheet.Shapes[addedShapes].Group();
See which ever works. I can't really figure out which one MSDN suggests.
Excuse the c style comments, the vb style doesnt syntax hilight nicely.
//This declares an array of variants but does not initialize it.
Dim addedshapes() As Variant
//Initializes the array with a max index of 1. (insert vb index rant here)
ReDim addedShapes(1)
//assigns the contents of aBracket.Name to element 1 of the array.
addedShapes(1) = aBracket.Name
//increases the size of addedShapes by 1, retaining any values.
ReDim Preserve addedShapes(UBound(addedShapes) + 1)
//sets the last element to the string literal
addedShapes(UBOund(addedShapes)) = "unique2"
//Not sure here because I havent done any VBA in a loooong time,
//but anyway it's passing the array.
set tmpShape = Me.Shapes.Range(addedShapes).Group
in VB, Variant is just a lazy struct that can hold any datatype, int, floats, objects, etc. so in .Net the most direct comparison would be some collection/array of objects. However if you know what is going in there then it's far better to limit the collection to that. So rather than List<object> you'd use List<Class> or List<BaseClass> or List<ISomeInterface>