如何在TList中存储动态数组?

WeG*_*ars 6 delphi delphi-7

我需要存储未知数量的组.每个组都有未知数量的元素/项目.这是我的'小组':

 TGroup= array of Integer;     <------ dynamic array (as you can see) :)
Run Code Online (Sandbox Code Playgroud)

我想用TList来保持我的团队.我的想法是,我可能希望稍后访问这些组并向其添加更多项目.

我有这个代码,但我不能让它工作:

TYPE
   TGroup= array of Integer;                              // Each group has x items (x can be from 1 to 10000)


procedure TForm1.FormCreate(Sender: TObject);
VAR CurGroup: TGroup;
    grp, item: Integer;
    Groups: TList;                                        // can contain up to 1 million groups
begin
 Groups:= TList.Create;

 { Init }
 for grp:= 1 to 4  DO                                     // Put a dummy item in TList
  begin
   SetLength(CurGroup, 1);                                // Create new group
   Groups.Add(@CurGroup);                                 // Store it
  end;

 CurGroup:= NIL;                                          // Prepare for next use

 for grp:= 1 to 4  DO                                     // We create 4 groups. Each group has 3 items
  begin
    CurGroup:= Groups[Groups.Count-1];                    // We retrieve the current group from list in order to add more items to it

    { We add few items }
    for item:= 0 to 2  DO
     begin
       SetLength(CurGroup, Length(CurGroup)+1);           // reserve space for each new item added
       CurGroup[item]:= Item;
     end;

    Groups[Groups.Count-1]:= @CurGroup;                   // We put the group back into the list
  end;

 { Verify }
 CurGroup:= NIL;
 CurGroup:= Groups[0];
 Assert(Length(CurGroup)> 0);                             // FAIL
 if  (CurGroup[0]= 0)
 AND (CurGroup[1]= 1)
 AND (CurGroup[2]= 2)
 then Application.ProcessMessages;                        

 FreeAndNil(Groups);
end;
Run Code Online (Sandbox Code Playgroud)

注意:代码已完成.您可以将其粘贴到Delphi(7)中进行试用.

All*_*uer 6

哦,这在新版本的Delphi中会更好......你会使用通用的TList <T>.var组:TList <TGroup>;

你最好的选择是使用另一个动态数组:组:TGroup数组;

原因是动态数组是编译器管理和引用计数.TList仅适用于指针.当试图将dynarrays放入TList时,没有直接的方法来保持引用计数的合理性.

您遇到的另一个问题是您将动态数组变量的堆栈地址添加到TList,而不是实际的数组.@CurGroup表达式是"CurGroup变量的地址",它是一个局部变量,位于堆栈中.


Arn*_*hez 4

我创建了一个围绕动态数组 RTTI 的包装器。

这只是初稿,但它的灵感来自于你的问题以及TList缺少方法的事实。

type
  TGroup: array of integer;

var 
  Group: TGroup;
  GroupA: TDynArray;
  i, v: integer;
begin
  GroupA.Init(TypeInfo(TGroup),Group); // associate GroupA with Group
  for i := 0 to 1000 do begin
    v := i+1000; // need argument passed as a const variable
    GroupA.Add(v);
  end;
  v := 1500;
  if GroupA.IndexOf(v)<0 then // search by content
    ShowMessage('Error: 1500 not found!');
  for i := GroupA.Count-1 downto 0 do
    if i and 3=0 then
      GroupA.Delete(i); // delete integer at index i
end;
Run Code Online (Sandbox Code Playgroud)

TDynArray包装器也适用于字符串数组或记录数组...记录只需要打包并且只有非引用计数字段(字节、整数、双精度...)或字符串引用计数字段(无变体或接口)之内)。

IndexOf() 方法将按内容搜索。也就是说,例如对于记录数组,所有记录字段(包括字符串)必须匹配。

请参阅TDynArray我们源代码存储库中的SynCommons.pas 单元。适用于 Delphi 6 到 XE,并处理 Unicode 字符串。

TTestLowLevelCommon._TDynArray方法是与该包装器相关的自动化单一测试。您将在此处找到记录数组示例和更高级的功能。

我目前正在实施SaveToStreamLoadToStream方法......

也许是在所有 Delphi 版本中使用类似通用功能的新方法。

编辑:

我向TDynArray记录/对象添加了一些新方法:

  • 现在您可以将动态数组内容保存到字符串或从字符串加载动态数组内容(使用LoadFromStream/SaveToStreamLoadFrom/SaveTo方法) - 它将使用专有但非常快的二进制流布局;
  • 您可以通过两种方式对动态数组内容进行排序:就地(即交换数组元素内容)或通过外部整数索引查找数组(使用方法CreateOrderedIndex- 在这种情况下,您可以有多个顺序相同的数据);
  • 您可以指定任何自定义比较函数,并且有一种新Find方法可以使用快速二分搜索(如果可用)。

这些新方法的工作原理如下:

var
  Test: RawByteString;
...
  Test := GroupA.SaveTo;
  GroupA.Clear;
  GroupA.LoadFrom(Test);
  GroupA.Compare := SortDynArrayInteger;
  GroupA.Sort;
  for i := 1 to GroupA.Count-1 do
    if Group[i]<Group[i-1] then
      ShowMessage('Error: unsorted!');
  v := 1500;
  if GroupA.Find(v)<0 then // fast binary search
    ShowMessage('Error: 1500 not found!');
Run Code Online (Sandbox Code Playgroud)

仍然更接近通用范例,速度更快,对于 Delphi 6 到 XE...