在Delphi中将Length()与多维动态数组一起使用

时间:2020-03-06 15:01:51  来源:igfitidea点击:

我在delphi中使用多维动态数组,并试图弄清楚这一点:

对于第一个索引和第二个索引,我有2个单独的值,它们彼此完全分开。

随着新值的到来,如果该新值在任一范围之外,我想增加数组。

对于新值x,y

我检查:

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

这是执行此操作的正确方法,还是有根据需要增加数组的更好方法?

解决方案

如果我们将最后一行更改为

SetLength(List, Length(List), y + 1);

我认为我们忘记了在第二维上使用第二个索引;

代码可能应如下所示:

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

请注意,在增大第二维时,将" x"用作第一维索引。

不过请注意以下几点:

我们应该意识到,Delphi也在动态数组上使用了引用计数(就像使用AnsiString一样)。
因此,可以像上面那样增长数组,但是对它的任何其他引用仍将具有它的旧副本!

解决此问题的唯一方法是使用一个额外的间接级别(即)来跟踪这些数组。 :使用指向动态数组的指针(本身也是一个指针,但是可以)。

还要注意,在动态数组的地址可能更改的任何情况下(例如使用SetLength()对其进行扩展/收缩时),都应更新这些"外部"指针中的任何一个。

@PatrickvL:
抱歉,但这完全是错误的。代码甚至没有编译,因为它试图为一维元素List [x]设置两个维度。 (PatrickvL更新了他的代码,因此答案的这一部分不再有效。)

以下代码演示了多维数组的大小调整。

程序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.

Delphi帮助也很好地解释了这一点(结构化类型,数组)。

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;