如何在TList中存储动态数组? [英] How to store dynamic arrays in a TList?

查看:136
本文介绍了如何在TList中存储动态数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要存储未知数量的组。每组具有未知数量的元素/项目。
这是我的'组':

  TGroup =整数数组; < ------动态数组(可以看到):) 

我想使用TList持有我的团体。这个想法是,我可能想要稍后访问这些组,并向他们添加更多的项目。



我有这个代码,但我不能使它工作: p>

  TYPE 
TGroup = Integer数组; //每个组都有x个项目(x可以是1到10000)


procedure TForm1.FormCreate(Sender:TObject);
VAR CurGroup:TGroup;
grp,item:Integer;
组:TList; //可以包含多达100万个组
begin
组:= TList.Create;

{Init}
for grp:= 1到4 DO //将一个虚拟项目放在TList
begin
SetLength(CurGroup,1); //创建新组
Groups.Add(@CurGroup); //存储
end;

CurGroup:= NIL; //准备下一个使用

为grp:= 1到4 DO //我们创建4组。每组有3个项目
begin
CurGroup:= Groups [Groups.Count-1]; //我们从列表中检索当前组,以便向其添加更多项目

{我们添加几个项目}
项目:= 0到2 DO
begin
SetLength(CurGroup,Length(CurGroup)+1); //为添加的每个新项目保留空间
CurGroup [item]:= Item;
结束

组[Groups.Count-1]:= @CurGroup; //我们将组放回列表
end;

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

FreeAndNil(Groups);
结束

注意:代码完成。您可以将其粘贴到Delphi(7)中以尝试。

解决方案

我已经在动态数组RTTI周围创建了一个包装器。



这只是第一稿,但它受到您的问题的启发,事实上, TList 方法是

  type 
TGroup:整数数组;

var
组:TGroup;
GroupA:TDynArray;
i,v:integer;
begin
GroupA.Init(TypeInfo(TGroup),Group); //将GroupA与Group
关联到i:= 0到1000 do begin
v:= i + 1000; //需要作为const变量传递的参数
GroupA.Add(v);
结束
v:= 1500;
如果GroupA.IndexOf(v)< 0 then //按内容搜索
ShowMessage('Error:1500 not found!');
for i:= GroupA.Count-1 downto 0 do
if i and 3 = 0 then
GroupA.Delete(i); //删除索引整数i
end;

这个 TDynArray 包装器也可以与数组字符串或记录数组...记录只需要打包,并且只有不引用计数字段(字节,整数,双精度)或字符串引用计数字段(无变体和接口内)。



IndexOf()方法将按内容进行搜索。例如对于一系列记录,所有记录字段(包括字符串)必须匹配。



请参阅 TDynArray =http://synopse.info/fossil/finfo?name=SynCommons.pas =nofollow> SynCommons.pas单元从我们的源代码存储库。从Delphi 6到XE,并处理Unicode字符串。



TTestLowLevelCommon._TDynArray 方法是自动化与此包装器相关联的单一测试。你会在这里找到一系列记录和更高级的功能。



我正在实现 SaveToStream LoadToStream 方法...



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

编辑:



我已经添加了一些新的方法到$ $ c> TDynArray record / object:




  • 现在,您可以保存并加载动态数组内容一个字符串(使用 LoadFromStream / SaveToStream LoadFrom / SaveTo 方法) - 它将使用专有但非常快的二进制流布局;

  • ,您可以通过两种方式对动态数组内容进行排序:即原位(即数组元素内容被交换)或通过外部整数索引查找数组(使用 CreateOrderedIndex 方法 - 在这种情况下,您可以使用相同数据的多个订单);

  • 可以指定任何自定义比较功能,还有一个新的 Find 方法将可以使用快速二进制搜索(如果可用)。



这些新方法如何工作:

  var 
测试:RawByteString;
...
测试:= GroupA.SaveTo;
GroupA.Clear;
GroupA.LoadFrom(Test);
GroupA.Compare:= SortDynArrayInteger;
GroupA.Sort;如果Group [i]< Group [i-1]然后
ShowMessage('Error:unsorted!'),则i:= 1到GroupA.Count-1 do
;
v:= 1500;
如果GroupA.Find(v)< 0 then // fast binary search
ShowMessage('Error:1500 not found!');

更接近于通用范式,更快,对于Delphi 6,直到XE ...


I need to store an unknown number of groups. Each group has an unknown number of elements/items. This is my 'group':

 TGroup= array of Integer;     <------ dynamic array (as you can see) :)

I want to use a TList to hold my groups. The idea is that I may want to access the groups later and add more items to them.

I have this code, but I can't make it work:

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;

Note: The code is complete. You can paste it in your Delphi (7) to try it.

解决方案

I've created a wrapper around dynamic array RTTI.

It's just a first draft, but it was inspired by your question, and the fact that the TList methods are missing.

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;

This TDynArray wrapper will work also with array of string or array of records... Records need only to be packed and have only not reference counted fields (byte, integer, double...) or string reference-counted fields (no Variant nor Interface within).

The IndexOf() method will search by content. That is e.g. for an array of record, all record fields (including strings) must match.

See TDynArray in the SynCommons.pas unit from our Source Code repository. Works from Delphi 6 up to XE, and handle Unicode strings.

And the TTestLowLevelCommon._TDynArray method is the automated unitary tests associated with this wrapper. You'll find out here samples of array of records and more advanced features.

I'm currently implementing SaveToStream and LoadToStream methods...

Perhaps a new way of using generic-like features in all Delphi versions.

Edit:

I've added some new methods to the TDynArray record/object:

  • now you can save and load a dynamic array content to or from a string (using LoadFromStream/SaveToStream or LoadFrom/SaveTo methods) - it will use a proprietary but very fast binary stream layout;
  • and you can sort the dynamic array content by two means: either in-place (i.e. the array elements content is exchanged) or via an external integer index look-up array (using the CreateOrderedIndex method - in this case, you can have several orders to the same data);
  • you can specify any custom comparison function, and there is a new Find method will can use fast binary search if available.

Here is how those new methods work:

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!');

Still closer to the generic paradigm, faster, and for Delphi 6 up to XE...

这篇关于如何在TList中存储动态数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆