tags:

views:

4270

answers:

3

I am using a multi-dimensional dynamic array in delphi and am trying to figure this out:

I have 2 seperate values for the first index and second index that are totally seperate of each other.

As new values come I want to grow the array if that new value is outside of either bound.

For new values x, y

I check:

if Length(List) < (x + 1) then
   SetLength(List, x + 1);
if Length(List[0]) < (y + 1) then
   SetLength(List, Length(List), y + 1);

Is this the correct way to do this or is there a better way to grow the array as needed?

+3  A: 

It looks fine to me - if you change the last line to

SetLength(List, Length(List), y + 1);
gabr
It might be that the question was edited, but your code-sample is no different from the last line in the question!?
PatrickvL
Yes, the question was edited and you can check the modifications by clicking the link right to the text 'edited' at the bottom of the question.
gabr
A: 

I think you forgot to use the second index on the second dimension;

Your code should probably read like this :

if Length(List) < (x + 1) then
   SetLength(List, x + 1);
if Length(List[x]) < (y + 1) then
   SetLength(List[x], y + 1);

Note the use of 'x' as the first dimension index when growing the second dimension.

One caution though :

You should be aware of the fact that Delphi uses reference-counting on dynamic arrays too (just like how it's done with AnsiString). Because of this, growing the array like above will work, but any other reference to it will still have the old copy of it!

The only way around this, is keeping track of these array's with one extra level of indirection - ie. : Use a pointer to the dynamic array (which is also a pointer in itself, but that's okay).

Also note that any of those 'external' pointers should be updated in any situation that the address of the dynamic array could change, as when growing/shrinking it using SetLength().

PatrickvL
You only have to call SetLength on a subdimension (i.e. SetLength(List[X], ...)) if you want to create ragged arrays - arrays where different indices have different subdimension lengths.Plus that would create twodimensional array to be inserted at List[x] (hopefully compiler would complain).
gabr
+1  A: 

@PatrickvL: Sorry, but that is just plain wrong. Your code does not even compile because it tries to set two dimensions for the single-dimensional element List[x]. (PatrickvL updated his code so this part of the answer is no longer valid.)

The following code demonstrates multidimensional array resizing.

program TestDimensions;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  List: array of array of integer;

begin
  //set both dimensions
  SetLength(List, 3, 2);
  Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 3, Y = 2
  //set main dimension to 4, keep subdimension untouched
  SetLength(List, 4);
  Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 4, Y = 2
  //set subdimension to 3, keep main dimenstion untouched
  SetLength(List, Length(List), 3);
  Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 4, Y = 3
  //all List[0]..List[3] have 3 elements
  Writeln(Length(List[0]), Length(List[1]), Length(List[2]), Length(List[3])); //3333
  //you can change subdimension for each List[] vector
  SetLength(List[0], 1);
  SetLength(List[3], 7);
  //List is now a ragged array
  Writeln(Length(List[0]), Length(List[1]), Length(List[2]), Length(List[3])); //1337
  //this does not even compile because it tries to set dimension that does not exist!
//  SetLength(List[0], Length(List[0]), 12);
  Readln;
end.

The Delphi help also explains this quite nicely (Structured Types, Arrays).

Multidimensional Dynamic Arrays To declare multidimensional dynamic arrays, use iterated array of ... constructions. For example,

type TMessageGrid = array of array of string;
var Msgs: TMessageGrid;

declares a two-dimensional array of strings. To instantiate this array, call SetLength with two integer arguments. For example, if I and J are integer-valued variables,

SetLength(Msgs,I,J);

allocates an I-by-J array, and Msgs[0,0] denotes an element of that array.

You can create multidimensional dynamic arrays that are not rectangular. The first step is to call SetLength, passing it parameters for the first n dimensions of the array. For example,

var Ints: array of array of Integer;
SetLength(Ints,10);

allocates ten rows for Ints but no columns. Later, you can allocate the columns one at a time (giving them different lengths); for example

SetLength(Ints[2], 5);

makes the third column of Ints five integers long. At this point (even if the other columns haven't been allocated) you can assign values to the third column - for example, Ints[2,4] := 6.

The following example uses dynamic arrays (and the IntToStr function declared in the SysUtils unit) to create a triangular matrix of strings.

var
A : array of array of string;
I, J : Integer;
begin
SetLength(A, 10);
for I := Low(A) to High(A) do
begin
SetLength(A[I], I);
for J := Low(A[I]) to High(A[I]) do
A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' ';
end;
end;

gabr
Thanks for pointing this out; I'm so used to using ragged array's, that it never occurred to me that Delphi also allows cube-like arrays.Still, reading back the question, it seems that ragged arrays *where* the topic, so my comment still holds, if only after a little fixup (pfew!)Cheers!
PatrickvL
I agree - question wording seems to be a probleme here. It is completely possible that your interpretation of the question is correct.
gabr