11 Replies - 5031 Views - Last Post: 30 September 2009 - 11:58 AM Rate Topic: -----

#1 AlexG788  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 76
  • Joined: 28-January 09

multi dim array

Posted 24 September 2009 - 12:14 PM

I'm having some trouble resizing a multi dimentional array... I made a little test proc below with a 2-D array:


		Dim x = UBound(TxnTaskChangeArray)

		ReDim Preserve TxnTaskChangeArray(DataGridView1.Rows.Count + x, 3)
		For i = 1 To DataGridView1.Rows.Count
			For j = 1 To DataGridView1.Columns.Count
				TxnTaskChangeArray((i + x) - 1, j - 1) = DataGridView1.Item(j - 1, i - 1).Value
			Next
		Next

		ReDim Preserve TxnTaskChangeArray(DataGridView1.Rows.Count + x, 3)


		'display array data in another grid after save
		DataGridView3.Rows.Clear()
		DataGridView3.RowCount = UBound(TxnTaskChangeArray)
		DataGridView3.ColumnCount = 3

		For i = 1 To DataGridView3.Rows.Count
			For j = 1 To DataGridView3.Columns.Count
				DataGridView3.Item(j - 1, i - 1).Value = TxnTaskChangeArray(i - 1, j - 1)
			Next
		Next




so somewhere in my app i declared the TxnTaskChangeArray as:

Public TxnTaskChangeArray(0,3) as String

This is what the array is set to when I open the app... I then have a datagrid with 3 columns to which I add several rows... I add data to those rows and press a button to call the above procedure... x then = the number of rows in the array already (which on 1st run will be 0) and then adds the new rows... the second datagrid (or datagridview3 in the above code) shows the total array every time i update it...

My problem is that if i keep the code the way it is, i will get an error that says (you can only resize the right most dimension of the array)... I'm not changing it though... its always staying as 3.. If I take out the piece of code that says redim (the first instance of it) and leave the redim at the end of the procedure, every row above the most current update is taken out..

heeeeeelp! thanks as always :)

Is This A Good Question/Topic? 0
  • +

Replies To: multi dim array

#2 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2268
  • View blog
  • Posts: 9,482
  • Joined: 29-May 08

Re: multi dim array

Posted 24 September 2009 - 12:34 PM

This tutorial on Arrays should explain.
Was This Post Helpful? 0
  • +
  • -

#3 AlexG788  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 76
  • Joined: 28-January 09

Re: multi dim array

Posted 25 September 2009 - 08:24 AM

View PostAdamSpeight2008, on 24 Sep, 2009 - 11:34 AM, said:

This tutorial on Arrays should explain.



I think I read this one before, or atleast something very similar... it seems a bit counterintuative though, which is why I dont think I'm understanding correctly...

if i have an array defined as TestArray(10,3) then I have an array that has 10 rows and 3 columns right? so according to the rules of Redim Preserve, I can increase the amount of columns but not rows? that doesn't seem logical, is this correct?
Was This Post Helpful? 0
  • +
  • -

#4 mark.bottomley  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 176
  • View blog
  • Posts: 990
  • Joined: 22-April 09

Re: multi dim array

Posted 25 September 2009 - 09:15 AM

You are correct in your assumption. The limitation is in the implementation of the array. Back in the days of Fortran, a multi-dimensional array was always rectangular (all elements of a given dimension wer the same length) and implemented as consecutive memory locations. e.g. a 2x2 array of:
R1C1, R1C2
R2C1, R2C2
would be stored in memory as R1C1, R1C2, R2C1, R2C2. (Yes, I know that Fortran actual stored them in Column major order, but that just confuses my point). A VB 2x2 array is stored as an array of pointers to an array of elements e.g.
POINTERROW1, POINTERROW2
R1C1, R1C2
R2C1, R2C2
Access is performed by following pointers until you increment into the final Row using an index. It takes up more space and is slower, but it allows ragged arrays and better supports arrays with missing elements/dimensions.

Could they have allowed ReDim at any level, yes, but it is very difficult to implement efficiently.
Was This Post Helpful? 0
  • +
  • -

#5 AlexG788  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 76
  • Joined: 28-January 09

Re: multi dim array

Posted 25 September 2009 - 12:20 PM

View Postmark.bottomley, on 25 Sep, 2009 - 08:15 AM, said:

You are correct in your assumption. The limitation is in the implementation of the array. Back in the days of Fortran, a multi-dimensional array was always rectangular (all elements of a given dimension wer the same length) and implemented as consecutive memory locations. e.g. a 2x2 array of:
R1C1, R1C2
R2C1, R2C2
would be stored in memory as R1C1, R1C2, R2C1, R2C2. (Yes, I know that Fortran actual stored them in Column major order, but that just confuses my point). A VB 2x2 array is stored as an array of pointers to an array of elements e.g.
POINTERROW1, POINTERROW2
R1C1, R1C2
R2C1, R2C2
Access is performed by following pointers until you increment into the final Row using an index. It takes up more space and is slower, but it allows ragged arrays and better supports arrays with missing elements/dimensions.

Could they have allowed ReDim at any level, yes, but it is very difficult to implement efficiently.



that makes sense, but still a bit strange because it would seem that adding columns to an already filled array would be more hazerdous to an array structure than adding rows... if add a column, all values in that column for pre determined rows would be blank, hense yielding a set of missing data issues, but adding a row means i have the oppertunity to add the datapoints for each column consecutively... in any case, i sort of understand what you are saying... i can't say it reconsiles fully in my mind with how i see a database (which in essence is just an array) working, but there are always other avenues to follow.

Thanks!
Was This Post Helpful? 0
  • +
  • -

#6 mark.bottomley  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 176
  • View blog
  • Posts: 990
  • Joined: 22-April 09

Re: multi dim array

Posted 25 September 2009 - 02:01 PM

The limitation of VB arrays is that you can only ReDim the right-most array index. For rectangular 2-D arrays, you could implement them as a 1D array and perform the rowLength*rowIndex + colIndex yourself to find the element. You could then add rows easily, but adding columns would require some fancy logic.

Row/Column can be really confusing - major index/minor index might be better. (e.g. x,y for points is really column,row when you look at it on screen).
Was This Post Helpful? 0
  • +
  • -

#7 AlexG788  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 76
  • Joined: 28-January 09

Re: multi dim array

Posted 29 September 2009 - 07:34 AM

View Postmark.bottomley, on 25 Sep, 2009 - 01:01 PM, said:

The limitation of VB arrays is that you can only ReDim the right-most array index. For rectangular 2-D arrays, you could implement them as a 1D array and perform the rowLength*rowIndex + colIndex yourself to find the element. You could then add rows easily, but adding columns would require some fancy logic.

Row/Column can be really confusing - major index/minor index might be better. (e.g. x,y for points is really column,row when you look at it on screen).



Mark this sounds like what I need, can you give me a code example of how that array would look? I'm not sure I understand the part about implementing it as a 1D array and then referencing the columns/rows. I think my only other real solution to this issue is to set up a table in the db and then reference it in a dataset (without having to write back to the db) and just adding/subtracting rows from that... its basically the same principle except that I don't have to worry about losing data with the addition of new rows... the only problem is that I don't necessarily want to ref a db table that I'm not actively using...

Thanks!
Was This Post Helpful? 0
  • +
  • -

#8 mark.bottomley  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 176
  • View blog
  • Posts: 990
  • Joined: 22-April 09

Re: multi dim array

Posted 29 September 2009 - 08:12 AM

The question here is "Do you need an array?". If you use the major dimension, the rows in this case, as a list (unordered, expandable/contractible array), then you may have solved the problem.

As for the 1D array - e.g. you want an array 10x3 then create a 1-D array of 30 elements. You will need to create a class to hold the array with methods like this (untested code):
Public Sub Read(ByVal Row As Integer, ByVal Col As Integer) As <whateverthe array content type is>
  return myArray(Row * RowSize + Column) ' or Col * ColSize + Row depending on your view.
End Sub

Public Sub InsertRow(ByVal NewRowIndex As Integer)
  ReDim Preserve myArray(myArray.Count + RowSize) ' create space for a new row
  ' copy the rows from the end, down to the new row to make room - there are likely some optimized ways to do this.
  For I = MyArray.Count - 1 To (NewRowIndex + 1) * RowSize Step -1
	myArray(I) = myArray(I - RowSize)
  Next
End Sub


There may be some difficulty in assigning it it the Grid Control, but that is a different problem.

I would help to know more about the specific data and the usage to see if there is a better way to store/manipulate the dats.

This post has been edited by mark.bottomley: 29 September 2009 - 08:13 AM

Was This Post Helpful? 0
  • +
  • -

#9 AlexG788  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 76
  • Joined: 28-January 09

Re: multi dim array

Posted 29 September 2009 - 12:34 PM

View Postmark.bottomley, on 29 Sep, 2009 - 07:12 AM, said:

The question here is "Do you need an array?". If you use the major dimension, the rows in this case, as a list (unordered, expandable/contractible array), then you may have solved the problem.

As for the 1D array - e.g. you want an array 10x3 then create a 1-D array of 30 elements. You will need to create a class to hold the array with methods like this (untested code):
Public Sub Read(ByVal Row As Integer, ByVal Col As Integer) As <whateverthe array content type is>
  return myArray(Row * RowSize + Column) ' or Col * ColSize + Row depending on your view.
End Sub

Public Sub InsertRow(ByVal NewRowIndex As Integer)
  ReDim Preserve myArray(myArray.Count + RowSize) ' create space for a new row
  ' copy the rows from the end, down to the new row to make room - there are likely some optimized ways to do this.
  For I = MyArray.Count - 1 To (NewRowIndex + 1) * RowSize Step -1
	myArray(I) = myArray(I - RowSize)
  Next
End Sub


There may be some difficulty in assigning it it the Grid Control, but that is a different problem.

I would help to know more about the specific data and the usage to see if there is a better way to store/manipulate the dats.


hehe.. prepare yourself!
I have a transaction table linked to a datagridview. col # 2 (for example) is a combobox column, so for each line item the user can go in, change the value and another box pops up where they can store up to 10 predefined tasks for which the amount in the transaction was charged and how much each of the total transaction (invoice) was allocated to that task... so for example:

Txn ID | Status (cmbo box) | Ttl Txn $ | Vendor

XX555 Allocated 5,000,000 ABC Corp


If the user selected "Allocated" from the drop down (which has two options, "Allocated" and "Unallocated") then a box pops up with a datagridview which allows users to add subtract or edit the tasks... 1st column in the dgv is ofcourse a combobox which has the 10 task options... if the user chooses one, and decides to add another task, the 1st task will no longer be available there... and so on in that fashion.. The total of the allocated tasks must equal 5,000,000

My problem is this.. I have an allocation table in my database (along with that transaction table that i mentioned earlier)... when the user saves the pop up box, currently the changes to the allocation table are made to the db right away.... So if I had 10 tasks in there before, and now removed 5 and reallocated the 5mill, I need to have that reflected in the allocation table.. What I currently do is.. upon opening the pop up box, filling a dataset with the multiple rows in the allocation table with the txn id on it that corresponds to the txn id on the main form's datagrid view (where I selected "Allocated"). when I make changes to the pop up box, I click save, and my dataset is deleted, and replaced with the values currently in the datagridview. My problem here is that if I don't also click save on the main form, I could have mismatched values... for example, if a user allocated the txn, saved the data to the allocation table, and then didn't save the main form and closed it... what i have is a transaction saying that it is not allocated, but with allocation records in the allocation table.. this is bad.

So what I decided to do was... everytime a pop up box is opened and changes are made, those changes get copied over into an interim array... changes get added to that array everytime a popup box is saved, without deleting previous records. When the user clicks "save" on the main form, the changes are made to the allocation table from this array... if the user never clicks "save" and just closes the form, the changes are lost (of course there is the "are you sure you don't want to save...blah blah" dialogs that come up). but in this way, i don't have any orphaned records!

Believe it or not, but this is actually the short version :)
Was This Post Helpful? 0
  • +
  • -

#10 mark.bottomley  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 176
  • View blog
  • Posts: 990
  • Joined: 22-April 09

Re: multi dim array

Posted 29 September 2009 - 06:02 PM

If I understand your description (big if...) then there is a maximum number of changes.adds.deletes a user can do on the tasks for a transaction. Make the array large enough to hold all the variants and avoid grow/shrink code. You can scan the array for each of the next possible outputs to verify them for submission to the data base, or use some key on the task list to sort them prior to database commit, or on individual updates, scan the task list to find the one you want to overwrite.

Hope that makes some sense...
Was This Post Helpful? 0
  • +
  • -

#11 crepitus  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 85
  • View blog
  • Posts: 383
  • Joined: 08-September 09

Re: multi dim array

Posted 30 September 2009 - 01:46 AM

The scenario is a bit complicated, I think we would need a screenshot and sample data to get a good idea of what is going on.

If the situation is too complicated for databinding then...

I would use a class for the line items (you can probably think of a less vague name). Whenever you see a bunch of data that lives together in the business domain, then you should think about sticking it all in a class with the things as properties.

Working with arrays, multidimensional, flat, or jagged is just too low level and confusing. A class can store all the properties of a LineItem, and then you can use the collection types to store all the line items. E.g. a List(Of LineItem).

Public Enum AllocationStatus
	Unallocated
	Allocated
End Enum

Public Class LineItem

	' To do a property quickly, type prop then tab tab
	' To do a readonly property quickly, type propread then tab


	Private m_transactionId As String
	Public Property TransactionId() As String
		Get
			Return m_transactionId
		End Get
		Set(ByVal value As String)
			m_transactionId = value
		End Set
	End Property

	Private m_allocationStatus As AllocationStatus
	Public Property AllocationStatus() As AllocationStatus
		Get
			Return m_allocationStatus
		End Get
		Set(ByVal value As AllocationStatus)
			m_allocationStatus = value
		End Set
	End Property

	Private m_transactionTotal As Integer
	Public Property TransactionTotal() As Integer
		Get
			Return m_transactionTotal
		End Get
		Set(ByVal value As Integer)
			m_transactionTotal = value
		End Set
	End Property

	Private m_vendorName As String
	Public Property VendorName() As String
		Get
			Return m_vendorName
		End Get
		Set(ByVal value As String)
			m_vendorName = value
		End Set
	End Property

	' Add any constructors that you are likely to use
	Public Sub New(ByVal transactionId As String, ByVal allocationStatus As AllocationStatus, _
				   ByVal transactionTotal As Integer, ByVal vendorName As String)
		Me.TransactionId = transactionId
		Me.AllocationStatus = allocationStatus
		Me.TransactionTotal = transactionTotal
		Me.VendorName = vendorName
	End Sub

	' Equality methods are helpful
	Public Overrides Function Equals(ByVal obj As Object) As Boolean
		Dim other As LineItem = TryCast(obj, LineItem)
		If other Is Nothing Then Return False
		Return Me.AllocationStatus = other.AllocationStatus AndAlso _
			Me.TransactionId = other.TransactionId AndAlso _
			Me.TransactionTotal = other.TransactionTotal AndAlso _
			Me.VendorName = other.VendorName
		Return MyBase.Equals(obj)
	End Function

	' Return some string representation for debugging.
	Public Overrides Function ToString() As String
		Return String.Concat("("c, TransactionId, ", ", AllocationStatus, _
							 ", ", TransactionTotal, ", ", VendorName)
	End Function

	' You might want to override GetHashCode
	' You might want to implement IComparer so that you can sort a list of lineItems
	' You might want to add methods to persist the item to the database

End Class


Then you can add new ones to a list:
Dim lineItems As New List(Of LineItem)
Dim l As New LineItem("XX555", AllocationStatus.Allocated, 5000000, "ABC Corp")
lineItems.Add(l)

Was This Post Helpful? 0
  • +
  • -

#12 AlexG788  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 76
  • Joined: 28-January 09

Re: multi dim array

Posted 30 September 2009 - 11:58 AM

View Postcrepitus, on 30 Sep, 2009 - 12:46 AM, said:

The scenario is a bit complicated, I think we would need a screenshot and sample data to get a good idea of what is going on.

If the situation is too complicated for databinding then...

I would use a class for the line items (you can probably think of a less vague name). Whenever you see a bunch of data that lives together in the business domain, then you should think about sticking it all in a class with the things as properties.

Working with arrays, multidimensional, flat, or jagged is just too low level and confusing. A class can store all the properties of a LineItem, and then you can use the collection types to store all the line items. E.g. a List(Of LineItem).

Public Enum AllocationStatus
	Unallocated
	Allocated
End Enum

Public Class LineItem

	' To do a property quickly, type prop then tab tab
	' To do a readonly property quickly, type propread then tab


	Private m_transactionId As String
	Public Property TransactionId() As String
		Get
			Return m_transactionId
		End Get
		Set(ByVal value As String)
			m_transactionId = value
		End Set
	End Property

	Private m_allocationStatus As AllocationStatus
	Public Property AllocationStatus() As AllocationStatus
		Get
			Return m_allocationStatus
		End Get
		Set(ByVal value As AllocationStatus)
			m_allocationStatus = value
		End Set
	End Property

	Private m_transactionTotal As Integer
	Public Property TransactionTotal() As Integer
		Get
			Return m_transactionTotal
		End Get
		Set(ByVal value As Integer)
			m_transactionTotal = value
		End Set
	End Property

	Private m_vendorName As String
	Public Property VendorName() As String
		Get
			Return m_vendorName
		End Get
		Set(ByVal value As String)
			m_vendorName = value
		End Set
	End Property

	' Add any constructors that you are likely to use
	Public Sub New(ByVal transactionId As String, ByVal allocationStatus As AllocationStatus, _
				   ByVal transactionTotal As Integer, ByVal vendorName As String)
		Me.TransactionId = transactionId
		Me.AllocationStatus = allocationStatus
		Me.TransactionTotal = transactionTotal
		Me.VendorName = vendorName
	End Sub

	' Equality methods are helpful
	Public Overrides Function Equals(ByVal obj As Object) As Boolean
		Dim other As LineItem = TryCast(obj, LineItem)
		If other Is Nothing Then Return False
		Return Me.AllocationStatus = other.AllocationStatus AndAlso _
			Me.TransactionId = other.TransactionId AndAlso _
			Me.TransactionTotal = other.TransactionTotal AndAlso _
			Me.VendorName = other.VendorName
		Return MyBase.Equals(obj)
	End Function

	' Return some string representation for debugging.
	Public Overrides Function ToString() As String
		Return String.Concat("("c, TransactionId, ", ", AllocationStatus, _
							 ", ", TransactionTotal, ", ", VendorName)
	End Function

	' You might want to override GetHashCode
	' You might want to implement IComparer so that you can sort a list of lineItems
	' You might want to add methods to persist the item to the database

End Class


Then you can add new ones to a list:
Dim lineItems As New List(Of LineItem)
Dim l As New LineItem("XX555", AllocationStatus.Allocated, 5000000, "ABC Corp")
lineItems.Add(l)



What I'm doing is a bit different from the above sample, but the solution fits perfectly! Making a generic list solves my problems... With the "Find All" object, I have everything I need and cann add subtract without having to redim an array.

Thanks again!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1