For Each loop on a 2D array in VB.NET - vb.net

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.

Related

Remove an object from a List(of) based on object value

How do I remove an object from a list based on value, I'me getting an index out of range error
'A class called Person exists'
Dim PersonOne As New Person
PersonOne.name = "John"
PersonOne.age = 50
'Created a list to store them'
Dim MyList As New List(Of Person)
MyList.Add(PersonOne)
'Now to remove an object'
Dim ObjectToRemove As String = "John"
For Each item in MyList
If String.Compare(item.name, ObjectToRemove) = 0 Then
'How do I get the index to remove?'
End If
Next
Excuse the code, I bashed it out off the top of my head, my original code is a bit more convoluted. But the gist is I just want to compare a value, if it matches remove that . object from the List(Of).
Use the FindIndex method which accepts a predicate delegate. You can pass a lambda function for the predicate delegate.
(Also, I think it's clearer to use String.Equals with an explicit StringComparison instead of using String.Compare(x,y) == 0 as it signals intent better).
Dim personOneHasThisIndex As Integer
personOneHasThisIndex = MyList.FindIndex( Function(p) p.name.Equals( ObjectToRemove, StringComparison.Ordinal ) )
If personOneHasThisIndx > -1 Then
' Always check if the result is -1, which means it doesn't exist
MyList.RemoveAt( personOneHasThisIndex )
End If
Note that List<T>.RemoveAt(Int32 index) is inefficient because it has to move every element in the List (lists cannot have "empty" spaces). If you have a conceptual list you'll be adding and removing from a lot, consider using LinkedList or a HashSet (if the order of the elements doesn't matter) instead.

Creating a new String Array from another

I have an array of integers (dfArray) and would like to create a new second String array which consists of the integers and appending "G" to the beginning. What's the best way to go about this? I was thinking of For Each but couldn't get it to work. Thanks in advance.
Set dfArray = [dff]
Set dfArray2 = ["G" & dff] 'incorrect but you get the idea?
Dim dfArray() As Variant
Dim dfArray2() As String
dfArray = [dff].Value
ReDim dfArray2(UBound(dfArray)) As String
Dim i As Double
For i = 1 To UBound(dfArray) Step 1
dfArray2(i) = "G" & dfArray(i, 1)
Next i
Anyways, from my personal point of view, I don't like to asign a complete Range into Array, only if needed. I prefer to loop using Lbound or Ubound and control the array all the time. To asign a range into an Array, you need the Array variable to be Variant type, and also, you can't use Preserve easily. Check this question for more info
Issues about Variant Arrays

2D arrays throws index out of bound exception

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

VB.NET Multi-Dimentional Array

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.

Unlimited Array Range VB.NET

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).