I Declare an 2D Unlimited array.
My code:
Dim array As String(,) = New String(,) {}
array(0, 0) = "top left"
MsgBox(array(0, 0))
The problem is the msgbox shows nothing.
You can change the array bounds when needed with ReDim Preserve, which copies the existing array into an array with new dimensions.
But it might be simpler to use a List instead, which is "unlimited" (no need to specify range, or resize manually). But a list only has one dimension. To mimick a 2D array, you could have a List of Lists (each List item is a List itself).
Related
I'm making a program and I keep getting the error Index was outside the bounds of the array and I can't figure out why. I tried all the different versions of setting up my 2D array.
Here is how I have it set up now
Dim dataArray(,) As Array = New Array(,) {{}}
Here is my loop for it
Dim x As Integer
Dim DT As DataTable
Dim TA As New DSOldOrdersTableAdapters.TA
DT = getOldOrders()
For x = 0 To DT.Rows.Count - 1
dataArray(0, x) = DT.Rows(x).Item("SO")
dataArray(1, x) = (DT.Rows(x).Item("Customer"))
dataArray(2, x) = (DT.Rows(x).Item("ShipBy"))
Next
You are declaring an array with a length of 0. That means that it will be unable to hold any data. All indexes will be out of range. Arrays do not automatically grow as items are added to them. As such, arrays should typically only be used in situations where the size of the array is fixed (unchanging). For instance:
Dim dataArray(2, 2) As Object ' Creates a 3x3 array of objects
If you want it to automatically grow as items are added, you would typically want to use a List(Of T) rather than an array. For instance:
Public Class MyItem
Public Property SO As Object
Public Property Customer As Object
Public Property ShipBy As Object
End Class
' ...
Dim dataList As New List(Of MyItem)()
' ...
Dim item As New MyItem()
item.SO = DT.Rows(x).Item("SO")
item.Customer = DT.Rows(x).Item("Customer")
item.ShipBy = DT.Rows(x).Item("ShipBy")
dataList.Add(item)
' ...
Label1.Text = dataList(1).SO
Or, if you insist on using an array to store each item, you can make a list of 1D arrays, like this:
Dim dataList As New List(Of Object())()
' ...
dataList.Add(
{
DT.Rows(x).Item("SO"),
DT.Rows(x).Item("Customer"),
DT.Rows(x).Item("ShipBy")
})
' ...
Label1.Text = dataList(1)(0)
As #Steven Doggart said (and beat me up to one minute with the answer) you are declaring an array, but you don't give the dimension length. You have two options:
specify the array dimension size at the declaration
or use Redim to set the (dimension) size of the array
In your case one solution could look like this:
Dim dataArray(,) As Array = New Array(3, DT.Rows.Count) {{}}
Or like this:
Dim dataArray(,) As Array = New Array(,) {{}}
Redim dataArray(3, DT.Rows.Count)
Dim x As Integer
Dim DT As DataTable
Dim TA As New DSOldOrdersTableAdapters.TA
DT = getOldOrders()
For x = 0 To DT.Rows.Count - 1
dataArray(0, x) = DT.Rows(x).Item("SO")
dataArray(1, x) = (DT.Rows(x).Item("Customer"))
dataArray(2, x) = (DT.Rows(x).Item("ShipBy"))
Next
Have a look at this MSDN Article - How to: Initialize an Array variable in VB.NET.
Dim dataArray(,) As Array = New Array(,) {{}}
This creates a two-dimensional array of Array, i.e. a two-dimensional array where each element is an Array. It's then initialized to an array containing a single, empty Array element. I expect this is not what you intended.
Since you never ReDim your array anywhere in the code to alter its dimensions, it remains a two-dimensional array whose first dimension is length 1, and whose second dimension is length zero.
When you try to run
dataArray(0, x) = DT.Rows(x).Item("SO")
The second dimension of the array has length zero, so it cannot hold a value. Thus you get an "index out of range" exception. If this did not happen, you would probably get another exception, because DT.Rows(x).Item("SO") probably is not an Array.
It would probably be easier to leave the data in the DataTable, and read from it whenever needed. Otherwise, I think your intent was to do something like:
Dim dataArray(0 To 3, -1) As Object 'Temporarily create a 2D Object array
'...load the DataTable
ReDim dataArray(0 to 3, 0 To DT.Rows.Count - 1) 'Redimension the array to the proper size.
'...rest of code
I have a parent class: CMove
I have a bunch of child classes that inherit CMove: M[Name of Move]
I have a dictionary: pMoveSet(of Stings, CMove)
The Values of the dictionary are New child classes: e.g. pMoveSet(Key1, New MTackle)
I want to set the instance from the dictionary to an array (as CMove) that holds instances of the child classes: PossMoves(i) = kvp.Value
I do this in a “For Each” loop over the dictionary where I check the keys to see if I want the value. If I want the value, I set the value of the kvp equal to an element of the array.
I have a msgbox that properly displays the array position and the name of the child object directly after the child object is added to the array.
My code leaves the loop and I imagine the array should carry all the relevant child classes of CMove that I want.
A msgbox identical to the one in the “For Each” loop crashes with the error “NullReferenceException was unhandled. Object reference not set to an instance of an object.”
It seems the instance that is created and applied to the array originally in the “For Each” loop is lost by the time the array is called again outside the loop.
How can I fix this? I would appreciate some clarity on how to handle this. The code is below.
Dim PossMoves() As CMove, kvp As KeyValuePair(Of String, CMove)
ReDim PossMoves(0)
For Each kvp In pMoveSet
If Val(kvp.Key) < pLvl Then
PossMoves(UBound(PossMoves)) = kvp.Value
MsgBox(UBound(PossMoves) & vbCrLf & PossMoves(UBound(PossMoves)).Name)
ReDim PossMoves(UBound(PossMoves) + 1) 'Will add unused element after the last possible move
End If
Next
ReDim Preserve PossMoves(UBound(PossMoves) - 1) 'Removes blank value at the top of array
MsgBox(UBound(PossMoves) & vbCrLf & PossMoves(UBound(PossMoves)).Name) 'Error on this line.
The problem is that you are not preserving the array when you resize it. Therefore, every time you resize it to add a new element to the array, it clears the array. To fix it, simply change:
ReDim PossMoves(UBound(PossMoves) + 1)
To:
ReDim Preserve PossMoves(UBound(PossMoves) + 1)
However, I would strongly recommend that you use a List(Of CMove) instead of an array. It will be easier to work with and more efficient as well:
Dim PossMoves As New List(Of CMove)()
For Each kvp As KeyValuePair(Of String, CMove) In pMoveSet
If Integer.Parse(kvp.Key) < pLvl Then
PossMoves.Add(kvp.Value)
End If
Next
First try
Dim holdValues() As Integer 'Doesn't Work
holdValues(1) = 55
Second try
Dim holdValues(-1) As Integer 'Gives me Index was outside the bounds of the array.
holdValues(1) = 55
I'm trying to do something similar to
Dim myString(-1) As String
But apparently this doesn't apply to integer arrays. I don't know what the size of the array will be, it wont get smaller but it will grow larger.
Any help will be appreciated, thank you!
You could use the Initializers shortcut:
Dim myValues As Integer() = New Integer() {55, 56, 67}
But if you want to resize the array, etc. then definately have a look at a List(Of Integer):
'Initialise the list
Dim myValues As New System.Collections.Generic.List(Of Integer)
'Shortcut to pre-populate it with known values
myValues.AddRange(New Integer() {55, 56, 57})
'Add a new value, dynamically resizing the array
myValues.Add(32)
'It probably has a method do do what you want, but if you really need an array:
myValues.ToArray()
you add the number to
holdValues(x) //x+1 will be size of array
so something like this
Dim array(2) As Integer
array(0) = 100
array(1) = 10
array(2) = 1
you can re-allocate the array to be bigger if needed by doing this.
ReDim array(10) as Integer
you'll have to add in your code when you should make your array bigger. You can also look into lists. Lists take care of this issue automatically.
here's some info on Lists: http://www.dotnetperls.com/list-vbnet
Hope this helps.
Also a link for general knowledge on arrays http://www.dotnetperls.com/array-vbnet
Alright, so I'm used to PHP where I can declare a multi-level array like $something[0][1] = "test";. I need to be able to accomplish the same thing, but I'm using VB.NET. How would I do this?
And sorry if this isn't what a multi-dimentional array is, I might be wrong at what it's called but that's what I want to do.
Thanks!
Multidimensional array in VB.Net...
Dim twoDimensionalArray(10, 10) As String
twoDimensionalArray(0, 1) = "test"
I rarely use arrays, however. More elegant solutions can typically be achieved using Lists, Dictionaries, or combinations of the two.
Update .
The (10, 10) is the upper bound of the array (the size is actually 11, 0 through 10). If you don't specify the bounds, you have to Redim Preserve the array when you want to add to it. That's one good thing about lists, you don't have to specify an initial size and you can add to them freely.
Here's a quick example of a list of lists.
Dim listOfLists As New List(Of List(Of String))
listOfLists.Add(New List(Of String)(New String() {"a", "b", "c"}))
listOfLists.Add(New List(Of String)(New String() {"d", "e", "f"}))
listOfLists.Add(New List(Of String)(New String() {"g", "h", "i"}))
'listOfLists(0)(0) = "a"
'listOfLists(0)(1) = "b"
'listOfLists(2)(1) = "h"
Just a plain sample with dynamic resizing of the array
Dim arr(0)() As String '** array declaration
For i As Integer = 0 To 100 '** Outer loop (for the 1st dimension)
For j As Integer = 0 To 1 '** inner loop (for the 2nd dimension)
ReDim Preserve arr(i) '** Resize the first dimension array preserving the stored values
ReDim Preserve arr(i)(j) '** Resize the 2nd dimension array preserving the stored values
arr(i)(j) = String.Format("I={0},J={1}", i, j) '** Store a value
Next
Next
In .NET Arrays are usually static and won't be automatically resized. (As for example in Javascript etc.) Therefore it's necessary to manually resize the array each time you want to add a new item, or specify the size at the beginning.
I'm writing a loop to go through the first array of a 2D loop, and I currently have it like this:
For Each Dir_path In MasterIndex(, 0)
'do some stuff here
Next
But it's giving me an error, saying it expects an expression in the first field. But that's what I'm trying to do, loop through the first field. How do I fix this? What would I put in there?
EDIT: to clarify, I'm specifically looking for the 0th element in the subarray of each array, that's why that second field is constantly 0.
You can accomplish this with nested For loops
Note: When using a For Each loop to iterate over elements in an array, the placeholder generated on each iteration is a copy of the value in the actual array. Changes to that value will not be reflected in the original array. If you want to do anything other than read the information you will need to use a For loop to address the array elements directly.
Assuming a two dimension array the following code example will assign a value to each element in each dimension.
Dim MasterIndex(5, 2) As String
For iOuter As Integer = MasterIndex.GetLowerBound(0) To MasterIndex.GetUpperBound(0)
'iOuter represents the first dimension
For iInner As Integer = MasterIndex.GetLowerBound(1) To MasterIndex.GetUpperBound(1)
'iInner represents the second dimension
MasterIndex(iOuter, iInner) = "This Isn't Nothing" 'Set the value
Next 'iInner
'If you are only interested in the first element you don't need the inner loop
MasterIndex(iOuter, 0) = "This is the first element in the second dimension"
Next 'iOuter
'MasterIndex is now filled completely
You could optionally use the .Rank property to dynamically iterate over each dimension
If you want to loop over a jagged array like Konrad Rudolph was suggesting (This functionally more closely matches array implementations in other more loosely typed languages like PHP)you could go about it like so:
'This is a jagged array (array of arrays) populated with three arrays each with three elements
Dim JaggedIndex()() As String = {
New String() {"1", "2", "3"},
New String() {"1", "2", "3"},
New String() {"1", "2", "3"}
}
For Each aOuter As String() In JaggedIndex
'If you are only interested in the first element you don't need the inner for each loop
Dim sDesiredValue As String = aOuter(0) 'This is the first element in the inner array (second dimension)
For Each sElement As String In aOuter
Dim sCatch As String = sElement 'Assign the value of each element in the inner array to sCatch
sElement = "This Won't Stick" 'This will only hold value within the context of this loop iteration
Next 'sElement
Next 'aOuter
'JaggedIndex is still the same as when it was declared
You simply can’t. Multi-dimensional arrays aren’t really supported in the .NET framework infrastructure. They seem to be tagged on as an afterthought. The best solution is often not to use them, and to use jagged arrays instead (arrays of arrays – Integer()() instead of Integer(,)).
You can use Enumerable.Range recursively to iterate the dimensions of an array.
Lets say we have a two dimensional grid (rows and columns) of Int.
We can iterate it as follows:
using System.Linq;
[TestMethod]
public void TestTwoDimensionalEnumeration()
{
int rowcount = 9;
int columncount = 9;
int[,] grid = new int[rowcount, columncount];
var enumerated =
Enumerable.Range(0, rowcount - 1).
SelectMany(ri => Enumerable.Range(0, columncount - 1).
Select(ci => new {
RowIndex = ri,
ColumnIndex = ci,
Value = grid[ri,ci]
}));
foreach (var item in enumerated)
{
System.Diagnostics.Trace.WriteLine("Row:" + item.RowIndex +
",Column:" + item.ColumnIndex +
",Value:" + item.Value);
}
}
The same logic can be applied to any number of dimensions.