ReDim of 2d Array

New to FreeBASIC? Post your questions here.
Post Reply
Iczer
Posts: 99
Joined: Jul 04, 2017 18:09

ReDim of 2d Array

Post by Iczer »

i have some troubles with resizing of 2d array - for some reason not all rows preserved after ReDim and i don't understand why:

Code: Select all

Dim aRezult() As String
Dim As Integer iRowNumber, iColumnNumber


FuncName(... , aRezult() As String, iRowNumber, iColumnNumber)



Function GetArray2d(... , aRezult() As String, ByRef iRowNumber As Integer, ByRef iColumnNumber As Integer) As Integer
	
	Dim As Integer iArraySise = 888, iArraySizeStep = 888, 
	
	
	iRowNumber = 0
	iColumnNumber = SomeFunc(...)
	
	ReDim aRezult(0 To iArraySise, 0 To (iColumnNumber-1))
	
	
	Do
		<step>
		If Done Or Error Then Exit Do
		
		iRowNumber += 1
		
		If iRowNumber > iArraySize Then
			iArraySize += iArraySizeSTEP
			ReDim Preserve aRezult(0 To iArraySize, 0 To (iColumnNumber-1))
		EndIf
		
		For iColumnNum As ULong = 0 to (iColumnNumber - 1)
			aRezult(iRowNumber,iColumnNum) = <...>
		Next 
	Loop
	' ........................................................................................
	Print "iRowNumber = ";iRowNumber,"iColumnNumber = ";iColumnNumber
	Print "iRowBound = ";LBound(aRezult,1);"/";UBound(aRezult,1),"iColumnBound = ";LBound(aRezult,2);"/";UBound(aRezult,2)
	' ........................................................................................
	For i As Integer = 0 To iRowNumber
		Print "aRezult("&Str(i)&",0) = ";aRezult(i,0),"(";aRezult(i,1);"/";aRezult(i,2);")"
	Next i
	' ........................................................................................
	ReDim Preserve aRezult(0 To iRowNumber, iColumnNumber-1) As String
	' ........................................................................................
	Print
	
	Print "iRowNumber = ";iRowNumber,"iColumnNumber = ";iColumnNumber
	Print "iRowBound = ";LBound(aRezult,1);"/";UBound(aRezult,1),"iColumnBound = ";LBound(aRezult,2);"/";UBound(aRezult,2)
	
	For i As Integer = 0 To iRowNumber
		Print "aRezult("&Str(i)&",0) = ";aRezult(i,0),"(";aRezult(i,1);"/";aRezult(i,2);")"
	Next i
	' ........................................................................................
	aRezult(0,0) = Str(iRowNumber)
	' ........................................................................................
End Function
function have output like this:

Code: Select all

iRowNumber =  6             iColumnNumber =  4
iRowBound =  0/ 888        iColumnBound =  0/ 3
aRezult(0,0) =              (/)
aRezult(1,0) = aaa             (0/179)
aRezult(2,0) = bbb             (0/8650)
aRezult(3,0) = ccc             (0/136115)
aRezult(4,0) = ddd             (0/3)
aRezult(5,0) = eee             (0/12837)
aRezult(6,0) = fff             (0/184817)

iRowNumber =  6             iColumnNumber =  4
iRowBound =  0/ 6          iColumnBound =  0/ 3
aRezult(0,0) =              (/)
aRezult(1,0) = aaa             (0/179)
aRezult(2,0) =              (/)
aRezult(3,0) =              (/)
aRezult(4,0) =              (/)
aRezult(5,0) =              (/)
aRezult(6,0) =              (/)
But why rows 2...6 become blank? I'm not changing number of columns and number of rows is correct...
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: ReDim of 2d Array

Post by Tourist Trap »

Iczer wrote:i have some troubles with resizing of 2d array - for some reason not all rows preserved after ReDim and i don't understand why
Hello, maybe some expert will give you the details, but first you must know that multidimensional arrays have some REDIM PRESERVE limitation. The documentation says:
ReDim Preserve may not work as expected in all cases:

Preserve's current behavior is to keep the original data contiguous in memory, and only expand or truncate the size of the memory.
Its behavior (with a single dimension) is well-defined only when the upper bound is changed. If the lower bound is changed, the current result is that the data is in effect shifted to start at the new lower bound.
With multiple dimensions, only the upper bound of only the first dimension may be safely increased. If the first dimension is reduced, the existing mappable data may be lost. If lower-order dimensions are resized at all, the effects can be hard to predict.
It's a little long time I havn't played with those things so don't blame me if I'm wrong, but I remember that if you use PLACEMENT NEW you may be able to get some control on the memory that will allow you to preserve the memory. However as said above, I'm not sure, and for the moment I can't find my test example of the time.

Ok it's the beginner board, maybe I should add a word about Placement New. Said quickly this command allows you to write data at a given variable memory. When you use Redim Preserve you probably want to stay at the adress of your first array item (this is where are your full array data). So ok your data is there and you can create new data there thanks to this command, so it gives you some control that should look like a redim preserve if used well (or it doesn't work, because I just can't remember well right now...).

Otherwise you will have to copy your data for each dimensions, make the redim, and paste your data back in the new area... A little slow, but still a (crap) workaround.

:-D
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: ReDim of 2d Array

Post by fxm »

Following a similar remark by a user, in May I added a short explanation in the documentation, just after the extract quoted above by Tourist Trap:
... With multiple dimensions, only the upper bound of only the first dimension may be safely increased. If the first dimension is reduced, the existing mappable data may be lost. If lower-order dimensions are resized at all, the effects can be hard to predict (because multidimensional arrays are stored in row-major order : values differing only in the last index are contiguous).
See also topic:
Let's exemplify the REDIM exclusion cases
Last edited by fxm on Aug 12, 2017 5:53, edited 2 times in total.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: ReDim of 2d Array

Post by dodicat »

Suggest creating a dedicated macro.
Just copy the array and insert the values in a new array.

E.G. for 2 dimensions:

Code: Select all




#macro redimpreserve(Array,D1,D2)
    scope
        dim as long A,B
        dim as typeof(array) copy(D1,D2)
        for A =  D1          
            for B =  D2  
                    if A>=lbound(Array,1) and A<=ubound(Array,1) then
                    if B>=lbound(Array,2) and B<=ubound(Array,2) then   
                        copy(A,B)=Array(A,B)
                    end if
                    end if
            next B
        Next A
        redim Array(D1,D2)
        For A = D1
            For B = D2
                    Array(A,B) = copy(A,B)
            next B
        Next A
    end scope
#endmacro

redim as double d(1 to 4,1 to 3)

for n as long=1 to 4
    for m as long=1 to 3
        d(n,m)=n+m 'set some values
    next
next

for n as long=lbound(d,1) to ubound(d,1)
    for m as long=lbound(d,2) to ubound(d,2)
        print d(n,m);
    next
    print
next

redimpreserve(d,0 to 8,0 to 4)

print

for n as long=lbound(d,1) to ubound(d,1)
    for m as long=lbound(d,2) to ubound(d,2)
        color iif(d(n,m),8,15)'highlight the original array
        print d(n,m);
    next
    print
next

redimpreserve(d,0 to 3,0 to 2)

print

for n as long=lbound(d,1) to ubound(d,1)
    for m as long=lbound(d,2) to ubound(d,2)
        color iif(d(n,m),8,15)'highlight the original array
        print d(n,m);
    next
    print
next
sleep



 
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: ReDim of 2d Array

Post by Tourist Trap »

fxm wrote:in June I added a short explanation in the documentation,
Hello fxm!

I know that I was trying to make a custom data buffer in a similar affair weeks ago. I explain, say you have 3 dimensions, so it's 3 blocks of data. Rather than making 3 arrays, we could just use one that would grant initially 100 slots (for instance) for each dimensions, in one unique data buffer containing 300 slots. If we reduce the size of any dimensions of the custom buffer, there is no problem and it's the use of erase, clear or placement new (fast things to write the buffer) that would be used to write data. Reading the data shouldn't be that hard if we have something to track the size of the buffers. And resizing would occure only if some redim is called that would ask for more space. If a dimension asks for 101 slots, we simply double the buffer size( 100 + 100 + 100 ---> 200 + 200 + 200). This resizing again would only be classical pointer management like allocate, or whatever, + one data copy but theorically rare so at no cost.

Placement new and clear, as far as I remember are really fast. Then the most often, resizing wouldn't occure. That seems to me a correct concept. And also a custom workaround for multdimensial arrays like what is told here. Do you agree with the principle? (before I may give it a try when I have time again)
dodicat wrote:Suggest creating a dedicated macro.
Nice. I must take record of this one!
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: ReDim of 2d Array

Post by fxm »

dodicat wrote:Suggest creating a dedicated macro.
Just copy the array and insert the values in a new array.
I think that is the best solution for that.
Iczer
Posts: 99
Joined: Jul 04, 2017 18:09

Re: ReDim of 2d Array

Post by Iczer »

Thanks!
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: ReDim of 2d Array

Post by fxm »

I just added a clarification in the documentation:
KeyPgRedim → fxm [Added in note#1 that "Redim Preserve" may change the array data location in memory]
... Preserve's current behavior is to keep the original data contiguous in memory, and only expand or truncate the size of the memory (if resizing is not possible, the whole original data block is first shifted to another memory location).
and also:
KeyPgPreserve → fxm [Updated "NOTE" (to match "Redim Preserve")]
Post Reply