2011-03-03 18 views
6

未知数のグループを保存する必要があります。各グループには未知数の要素/項目があります。 これは私の「グループ」である:私は私のグループを保持するためのTListを使用したい動的配列をTListに格納する方法は?

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

。アイデアは、後でグループにアクセスしてアイテムを追加したいということです。

私はこのコードを持っているが、私はそれを動作させることはできません。

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; 

注:コードは完了です。あなたはそれを試してあなたのDelphi(7)に貼り付けることができます。

+0

"グループ"とは、アイデンティティ要素とすべての要素が逆になるような関連マグマを意味しますか? –

+0

@アンドレアス - いいえ。私のグループは数字のリスト(配列)です。これは私の「グループ」の定義です。 TGroup =整数の配列。 – Ampere

答えて

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; 

このTDynArrayラッパーは、文字列またはレコードの配列の配列でも動作します...レコードのみを梱包する必要があるとだけカウントフィールド(バイト、整数、ダブル...)、または文字列参照を参照していませんカウントされたフィールド(バリアントもインターフェイスもありません)。

IndexOf()メソッドはコンテンツで検索します。それは例えばです。レコードの配列では、すべてのレコードフィールド(文字列を含む)が一致しなければなりません。

TDynArraythe SynCommons.pas unitのソースコードリポジトリから参照してください。 Delphi 6からXEまでを処理し、Unicode文字列を処理します。

TTestLowLevelCommon._TDynArrayメソッドは、このラッパーに関連付けられた自動化された単体テストです。ここではレコードの配列とより高度な機能のサンプルを見ていきます。

私は現在SaveToStreamLoadToStream方法...すべてのDelphiのバージョンでは、一般的な-などの機能を使用しての

おそらく、新しい方法を実装しています。

編集:

私はTDynArray記録/オブジェクトにいくつかの新しいメソッドを追加しました:

  • 今、あなたは、文字列またはから動的配列の内容を保存し、読み込むことができます(LoadFromStream/SaveToStreamを使用してまたはLoadFrom/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!'); 

より速く、およびデルファイ6 XEまで、一般的なパラダイムに近いです...

+0

http://synopse.info/forum/viewtopic.phpを参照してください。 pid = 1522 –

6

ああ、これはDelphiの新しいバージョンではもっとうれしいでしょう...一般的なTList <T>を使用します。 varグループ:TList <TGroup>;

他のダイナミックアレイを使用することをお勧めします。Groups:TGroupの配列。

動的配列はコンパイラで管理され、参照カウントされるためです。 TListはポインタでのみ動作します。 dynarrayをTListに入れようとしているときに参照カウントを無条件に保つための単純な方法はありません。

動的配列変数スタックアドレスを実際の配列ではなくTListに追加しているという別の問題があります。 @CurGroupという表現は、局所変数である「CurGroup変数のアドレス」であり、スタック上にある。

+0

+1。私は、最近のDelphiを使ってすぐに使えるものの解決策を見つけることをあきらめました。 –

+0

私はDelphi 2010を持っていません。 – Ampere

+0

私は 'array of TGroup'を使いました。しかし、TListに提案するように、私は 'TGroupの配列'から 'アップグレード'しました。私はTListでも動作させたい。 – Ampere

4

私はここでマシン上でD7を持っていませんが、この代わりに(コンソールテストアプリケーション - それはD7がそれを処理する方法がわからノーヒントや警告をXEにコンパイルではなく)のようなものを試してみてください。

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils, Classes; 

type 
    TGroup = array of Integer; 
    THolder=class(TObject) 
    Group: TGroup; 
    end; 

var 
    GroupList: TList; 
    i: Integer; 

begin 
    GroupList := TList.Create; 
    for i := 0 to 2 do 
    begin 
    GroupList.Add(THolder.Create); 
    with THolder(GroupList[GroupList.Count - 1]) do 
    begin 
     SetLength(Group, 3); 
     Group[0] := i; 
     Group[1] := i + 10; 
     Group[2] := i + 20; 
    end; 
    end; 
    for i := 0 to GroupList.Count - 1 do 
    begin 
    Writeln(i, ':0 ', THolder(GroupList[i]).Group[0]); 
    Writeln(i, ':1 ', THolder(GroupList[i]).Group[1]); 
    Writeln(i, ':2 ', THolder(GroupList[i]).Group[2]); 
    end; 
    // Not cleaning up list content, because we're exiting the app. 
    // In a real app, of course, you'd want to free each THolder in 
    // the list, or use a TObjectList and let it own the objects. 
    // You'd also want a try..finally to make sure the list gets freed. 
    GroupList.Free; 
    Readln; 
end. 
+0

私にとっては、Delphi 7で完全に合理的なアプローチです。 –

+0

なぜTObjectListを直接使用しませんでしたか? –

+0

@ A.Bouchez、それはOPが尋ねた質問ではなかったからです。質問は特にTListに関するものでした。私はTObjectListの提案をコメントとしてコードに追加しました。 –

4

もう1つのことは、TObjectListを使用することです。 TObjectListはオブジェクトのリストを格納できるため、TObjectの新しいクラスの子孫を作成し、これらのオブジェクトを使用してTObjectListを管理できます。

サムシング(未テスト)のような:

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; 

実際には、はsetLength(CurGroupが)新しいグループを作成しません:あなたは、コード

type TGroupArray : array of Integer; 

type TGroup = class(Tobject) 
    GroupArray : TGroupArray; 
end; 

GroupList : TobjectList; 

procedure TForm1.FormCreate(Sender: TObject);           
var CurGroup : TGroup; 
begin 

GroupList:= TObjectList.Create; 
CurGroup := TGroup.Create; 
SetLength(CurGroup.GroupArray,1); 
CurGroup.GroupArray[0] := 10; 

GroupList.Add(CurGroup); 

RetreiveGroup := GroupList.Items[0]; 
FreeandNil(GroupList); 
end; 

等...

+0

私はこのようにします。 "Name:String"のような属性を追加する必要があるときは、それをクラスであるTGroupに追加することができます。 –

1

。 既存のCurGroupを1つだけサイズ変更します。

したがって、@CurGroupは変更されません。常に、CurGroupが追加されたスタック上のいくつかのアドレスになります。同じアドレスを複数回リストに追加します。

だから、あなたはそのようなTGroupインスタンスの動的配列を作成する必要があります:

var GroupArray: array of TGroup; 

SetLength(GroupArray,4); 
for grp := 0 to high(GroupArray) do 
begin 
    SetLength(GroupArray[grp],1); 
    Groups.Add(@GroupArray[grp]); 
end; 

しかし、もちろん、GroupArrayはグループがそれを必要とするすべての時間の間に割り当てられたままにしなければなりません。このGroupArrayをスタックに作成すると、メソッドが終了しスタックが解放されたときにすべてのGroupArray []アイテムが解放されるため、おそらくこのGroupArrayをクラスのプロパティとして配置します。

もちろん、GroupArray []はTGroup項目へのより直接的なアクセスになります... Groups [i]はGroupArray [] ...と等しくなります。グループ[]内のポインタからTGroupアイテムのサイズを変更した場合、メモリリークが発生しないことはわかりません...

+0

こんにちはブーシェ。 "TGroupインスタンスの動的配列を作成する必要があります" - - - 実際これが私の初期コードです。それは完全に動作します。私はちょうどそれがAdd()メソッドを持っているので、配列の配列よりも面倒でないTListに "アップグレード"したいと思った。 – Ampere

+0

"SetLength(CurGroup)は新しいグループを作成しません" - - - そうです。私は大規模なプログラムからコードを読みやすくするために叫んだ。そのコードでは、リストを初期化するためにループを使用しないので(実際には同じ要素を複数回追加しないので)、リストの初期化は実際には正しいです。 - しかし、もう一度ありがとう! – Ampere

0

だから、基本的に誰もがは、配列の配列を作成することを提案していますTListを使用する代わりに。まあ、私はすでにそれをしています。 Add()があるので、配列の配列からTListに "アップグレード"したいだけでした。元のコードに戻るようです。 ありがとうございました。それぞれの回答に対して+1しています。

+1

さて、アレンはこの種のコードをより洗練させる新しいDelphiを提案します。 –

+0

はい。知っている。しかし、私はそれを持っていません。だから、この解決策は手元にありません(私にとって)。 – Ampere

+1

私はTObjectListを使用するように提案しました – Simon

関連する問題