Tree-like Datastructure (for use with VirtualTreeview)
Asked Answered
F

6

3

I have come to the point where I need to stop storing my data in a VCL component, and have an "underlying datastructure", as Mr. Rob Kennedy suggested.

First of all, this question is about "how do I make an underlying datastructure". :)

My hierachy consists of 2 levels of nodes.

Right now, I go thru my stuff by looping rootnodes, wherein I loop thru the rootnode's childnodes, to get what I need (Data). I would love to be able to store all my data in a so-called Underlying Datastructure, so that I can easily modify the entries using threads (I suppose I am able to do that?)

However, when looping through my entries (right now), the results are depending on the node's Checkstate - if I am using an underlying data structure, how do I know if my node is checked or not, when its my datastructure I loop thru, and not my nodes?

Let's say I wanted to use 2 levels.

This would be the Parent:

TRoot = Record
  RootName : String;
  RootId : Integer;
  Kids : TList; //(of TKid)
End;

And the kid:

TKid = Record
  KidName : String;
  KidId : Integer;
End;

Thats basically what I do now. Comments state that this is not the best solution, so I am open to suggestions. :)

I hope you understand my question(s). :)

Thanks!

Frivolity answered 19/3, 2011 at 22:29 Comment(15)
@Jeff, IMHO, your question is not understandable to anyone which didn't read your previous questions, for what you don't provide links (as a last resort), but it is preferable if you write each question as if it is the only question you posted here. That way the question will be easily answerable by anyone, but most important, it will be understandable for future readers.Backspace
@jach - I am glad that you tell me, will try to find the previous post. :)Frivolity
@Jeff: No offense, but if I have got things right, you are a beginner programmer -- but if you keep learning, you will (in a few years) master programming at a much more sophisticated level. Until then, however, I think it is wise not to try too hard things when there are simpler alternatives. Are you really sure that you cannot use a TListBox? I mean, if you need a more advanced control to display your data, like the Virtual TreeView, you should first have the data in some "underlaying datastructure".Bilbo
(cont.) An "Underlying Datastructure" isn't some magic thing associated with the virtual treeview, but something you use all the time when programming at a more advanced level -- all you do is to manage data by means of algorithms.Bilbo
This question looks useful: stackoverflow.com/questions/1841621Paulsen
@Andreas - Yes, I am a beginner. I already have my stuff stored in records, but my data will be destroyed with the tree.Frivolity
-1 because you accepted the wrong answer: you really need to learn about data structures, it's the only way to move forward. Yet you chose (again) the easiest path, you selected to use database technology and avoid the hard work. Normally I wouldn't care, but following your questions I noticed you managed to create some interesting stuff, there's no doubt in my mind you can handle a tree data structure. Take this downvote as a kick in the right direction.Epode
@Cosmin - I only marked it as answer because if I didnt, someone will come and tell me to accept one as an answer, like the last time. I don't want to look like a prick who does not apreciate any effort. I removed it now that I know I get slapped either way. My question is about datastructures, but since I was short on time, I decided to nest some TLists.Frivolity
@Cosmin (continued) Yet you chose (again) the easiest path, you selected to use database technology and avoid the hard work. I see why you make that assumption, however my comment above states otherwise. Also, I'm still fairly new here, and I am used to Forum rules, like "Don't doublepost, don't doublethread, don't this, do that".Frivolity
@Frivolity I feel sure that there are good freely available tree view data structures. I just don't personally know what they are. I have used tpSysTools before but I'm not sure how well it plays with modern Delphi.Paulsen
@David thanks mate. I see how things work here. I wouldn't say I am valued, as I havent answered anyone else's question yet, and I wish a question that I can answer will popup sometime :) I thought you guys made your own structures? What I did (that works with what I need) was create a Level 1 Record and a Level 2 Record, and the level 1 Record contains a TList of Level 2 Records. Is that a particularly decent way of doing it?Frivolity
@jeff I would probably always write my own. In fact my own codebase has a homegrown tree written by a colleague. Your solution is not good. You should first study how a linked list works and then move on to trees. Each node maintains references to its next sibling and its first child, and possibly also its parent. That's really all you need. Have you read any books on data structures?Paulsen
@David - Well, if my solution does what it's supposed to, and what I need, I don't see a reason to add more functionality than I will need? :) No, I haven't read anything to be honest.Frivolity
@Jeff, Even when you DO get an working answer, it's not in your best interest, nor in the best interest of the community to immediately accept an answer. Unless the problem's very simple, like, you should wait a day or two to accept an answer: maybe an better answer will show up! This is in fact the kind of question that benefits from multiple answers. For example I saw the question this morning, didn't have the time to deal with it, when I came back I saw the tick mark for an answer that suggests using a database. I hate it when people recommend databases as if they'd be a panacea.Epode
@Jeff, please edit the question and include some information about the data in your record. Ideally the whole record. If you do that I'd be able to revert my downvote (I'd like to revert it since you unchecked the database answer, but I can't do that since it's been more then 1 hour; if you edit SO allows me to reconsider the vote). I'll turn the -1 into a +1 and might even provide an answer of my own if the other experts don't do it first.Epode
E
10

The data structure you're requesting is very simple, it's so simple I'd recommend using the windows-provided TTreeView: it allows storing the text and an ID straight into the tree's node with no additional work.


Despite my recommendation to use the simpler TTreeView I'm going to provide my take on the data structure problem. First of all I'm going to use classes, not records. In your very short code sample you're mixing records and classes in a very unfrotunate way: When you make a copy of the TRoot record (assigning records makes complete copies, because records are allways treated as "values"), you're not making a "deep copy" of the tree: The complete copy of TRoot will contain the same Kids:TList as the original, because classes, unlike records, are references: you're coping the value of the reference.

An other problem when you have a record with an object field is life cycle management: A record doesn't have an destructor so you'll need an other mechanism to free the owned object (Kids:TList). You could replace the TList with an array of Tkid but then you'll need to be very careful when passing the monster record around, because you might end making deep copies of huge records when you least expect it.

In my opinion the most prudent thing to do is to base the data structure on classes, not records: class instances (objects) are passed around as references, so you can move them around all you want with no problems. You also get built-in life cycle management (the destructor)

The base class would look like this. You'll notice it can be used as either the Root or the Kid, because both Root and Kid share data: The both have a name and an ID:

TNodeClass = class
public
  Name: string;
  ID: Integer;
end;

If this class is used as an Root, it needs a way to store the Kids. I assume you're on Delphi 2010+, so you have generics. This class, complete with a list, looks like this:

type
  TNode = class
  public
    ID: integer;
    Name: string;
    VTNode: PVirtualNode;
    Sub: TObjectList<TNode>;

    constructor Create(aName: string = ''; anID: integer = 0);
    destructor Destroy; override;
  end;

constructor TNode.Create(aName:string; anID: Integer);
begin
  Name := aName;
  ID := anID;

  Sub := TObjectList<TNode>.Create;
end;

destructor TNode.Destroy;
begin
  Sub.Free;
end;

You might not immediately realize this, but this class alone is enough to implement a multi-level tree! Here's some code to fill up the tree with some data:

Root := TNode.Create;

// Create the Contacts leaf
Root.Sub.Add(TNode.Create('Contacts', -1));
// Add some contacts
Root.Sub[0].Sub.Add(TNode.Create('Abraham', 1));
Root.Sub[0].Sub.Add(TNode.Create('Lincoln', 2));

// Create the "Recent Calls" leaf
Root.Sub.Add(TNode.Create('Recent Calls', -1));
// Add some recent calls
Root.Sub[1].Sub.Add(TNode.Create('+00 (000) 00.00.00', 3));
Root.Sub[1].Sub.Add(TNode.Create('+00 (001) 12.34.56', 4));

You need a recursive procedure to fill the virtual tree view using this type:

procedure TForm1.AddNodestoTree(ParentNode: PVirtualNode; Node: TNode);
var SubNode: TNode;
    ThisNode: PVirtualNode;

begin
  ThisNode := VT.AddChild(ParentNode, Node); // This call adds a new TVirtualNode to the VT, and saves "Node" as the payload

  Node.VTNode := ThisNode; // Save the PVirtualNode for future reference. This is only an example,
                           // the same TNode might be registered multiple times in the same VT,
                           // so it would be associated with multiple PVirtualNode's.

  for SubNode in Node.Sub do
    AddNodestoTree(ThisNode, SubNode);
end;

// And start processing like this:
VT.NodeDataSize := SizeOf(Pointer); // Make sure we specify the size of the node's payload.
                                    // A variable holding an object reference in Delphi is actually
                                    // a pointer, so the node needs enough space to hold 1 pointer.
AddNodesToTree(nil, Root);

When using objects, different nodes in your Virtual Tree may have different types of objects associated with them. In our example we're only adding nodes of TNode type, but in the real world you might have nodes of types TContact, TContactCategory, TRecentCall, all in one VT. You'll use the is operator to check the actual type of the object in the VT node like this:

procedure TForm1.VTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var PayloadObject:TObject;
    Node: TNode;
    Contact : TContact;      
    ContactCategory : TContactCategory;
begin
  PayloadObject := TObject(VT.GetNodeData(Node)^); // Extract the payload of the node as a TObject so
                                                   // we can check it's type before proceeding.
  if not Assigned(PayloadObject) then
    CellText := 'Bug: Node payload not assigned'
  else if PayloadObject is TNode then
    begin
      Node := TNode(PayloadObject); // We know it's a TNode, assign it to the proper var so we can easily work with it
      CellText := Node.Name;
    end
  else if PayloadObject is TContact then
    begin
      Contact := TContact(PayloadObject);
      CellText := Contact.FirstName + ' ' + Contact.LastName + ' (' + Contact.PhoneNumber + ')';
    end
  else if PayloadObject is TContactCategory then
    begin
      ContactCategory := TContactCategory(PayloadObject);
      CellText := ContactCategory.CategoryName + ' (' + IntToStr(ContactCategory.Contacts.Count) + ' contacts)';
    end
  else
    CellText := 'Bug: don''t know how to extract CellText from ' + PayloadObject.ClassName;
end;

And here's an example why to store VirtualNode pointer to your node instances:

procedure TForm1.ButtonModifyClick(Sender: TObject);
begin
  Root.Sub[0].Sub[0].Name := 'Someone else'; // I'll modify the node itself
  VT.InvalidateNode(Root.Sub[0].Sub[0].VTNode); // and invalidate the tree; when displayed again, it will
                                                // show the updated text.
end;

You know have an working example for a simple tree data structure. You'll need to "grow" this data structure to suite your needs: the possibilities are endless! To give you some ideas, directions to explore:

  • You can turn the Name:string into a virtual method GetText:string;virtual and then create specialized descendants of TNode that override GetText to provide specialized behavior.
  • Create a TNode.AddPath(Path:string; ID:Integer) that allows you to do Root.AddPath('Contacts\Abraham', 1); - that is, a method that automatically creates all intermediary nodes to the final node, to allow easy creation of the tree.
  • Include an PVirtualNode into TNode itself so you can check rather the Node is "checked" in the Virtual Tree. This would be a bridge of the data-GUI separation.
Epode answered 20/3, 2011 at 19:39 Comment(23)
First of all, thanks for this answer! I will definitely give it a try when I get home. However, I read in the Virtual Treeview documentation, that using records is better than classes? I don't know what I'm supposed to believe, as I am still a newbie at this.Frivolity
@Jeff, a record might be better if you store the data in the treview node itself. If you move the data to a distinct data structure you'll be storing a pointer: Why would VT care if you store a pointer to a record or a pointer to an object instance?Epode
@Cosmin - I have been reading up about pointers (about.com), but I still don't see exactly how they work, when I read "If you move the data to a distinct data structure you'll be storing a pointer". Also, doesen't records take less memory?Frivolity
@Jeff: A record might take a few bytes less memory when compared with a similar class, but records don't have destructors and are passed around by value, not by reference. I thought I explained that in my answer. In my opinion classes are a better fit for tree data structure. Alternatively you can implement your own tree using pointers and records.Epode
"passed around by value, not by reference. - I'm choking on that part :P Also, regarding the Destruction of my TList's, I just loop thru them and Dispose+Delete each item in the lists at time-to-die.Frivolity
@Cosmin thats what I was trying to do.Frivolity
@Frivolity maybe you should give yourself a "target" and implement a tree structure using records and pointers. Of course, you should start by implementing a linked list first, so you get the hang of pointers and manual memory management.Epode
@daemon_x, thanks for the edit, but I had to change a few things in the code you added, most importantly the redundant code you introduced in AddNodesToTree. I also removed the PNode = ^TNode type declaration (and all references to it) because it's not necessary and I really don't like those double-pointer declarations. See the changed code in the sample VTGetText to see how I was able to get by without using PNode.Epode
@Cosmin - I know about that; both are just pointers. I wanted to show off that. The same you can do with Contact: TContact; declaration in VTGetText event and use e.g. with PayloadObject as TContact do after is class test.Angiology
@Cosmin - and you put a := in var declaration by mistake; I wanted to correct that, but edits here must be at least 6 chars and I have nothing more to say here :)Angiology
@daemon, TNode is a pointer, so PNode = ^TNode is actually a pointer to a pointer, so they're not both "just pointers". One's a pointer, one's a double-indirected pointer. And it would be the wrong type to use in VTGetText especially if you expect the payload to be TNode OR something else: a better choice would be PObject = ^TObject;Epode
@Cosmin - thanks for correcting me. I know what you mean; TNode is also a pointer - to the class instance.Angiology
@Cosmin - This method - arent you storing the data in the tree afterall? I thought that was what I was not supposed to do?Frivolity
@Jeff, I'm not storing the data in the Virtual Tree, I'm storing the data in TNode. The VT node only contains a pointer to the actual TNode.Epode
@Cosmin - Aah, I get it! However, will my Datastructure be threadsafe, without having to call Synchronize? Because we are using VT.AddChild(); which is a VT method (main thread), correct?Frivolity
@Jeff, no GUI work is thread safe, and data structures in themselves are not thread safe nor unsafe, code that uses data structures is or is not thread safe.Epode
@Cosmin - May I ask why you set the NoteDataSize to Pointer? :) I am getting an AV when I do the VT.AddChild in my TCategory.AddUser routine. :PFrivolity
@Jeff, I'm setting NodeDataSize to SizeOf(Pointer), not to Pointer. VT's nodes need to reserve space for whatever I'm planning to add, and since I'm planning to add a TNode reference, that's the amount of space I need (you can think of objects as always being pointers). I can't possibly know why you get an AV from your AddUser routine without seeing the code.Epode
@Cosmin - I got it all figured out. However I am not really satisfied with the memory usage of this thing. Will post a question about it so you can compare. :)Frivolity
@Cosmin - Since we are doing VT.AddChild(); I assume it is not threadsafe, correct? I am trying to get a solution that is threadsafe, that lets me add, clear, add, clear, etc, from my data structure in a thread, so the user wont notice it (the app would hang otherwise).Frivolity
@Jeff, VT.AddChild() is worst then "not thread safe": It's GUI work so it needs to be done from the main VCL thread. But that shouldn't be a problem, since it's very fast; Do your hard work in a thread, when it's time to show stuff to the user do the call to VT.AddChild() in Synchronize().Epode
@Cosmin - The AddChild is in my TCategory.AddUser(); function - should I Synchronize the AddUser function, or should I remove the AddChild from the AddUser, and do the AddChild outside the class? Which do you recommend?Frivolity
@CosminPrund thank's for this very clever solution please could you edit you answer to add how to free the node and it's objects I often get memory leaks and I could not figure out how to free the node using the OnFreeNode event...Mescal
S
4

I asked similar question here. I didn't got any useful answers so I decide to make my own implementation, which you can find here.

EDIT: I'll try to post example how you could use my data structure:

uses
  svCollections.GenericTrees;

Declare your data type:

type
  TMainData = record
    Name: string;
    ID: Integer;
  end;

Declare your main data tree object somewhere in your code:

MyTree: TSVTree<TMainData>;

Create it (and do not forget to free later):

MyTree: TSVTree<TMainData>.Create(False);

Assign your VirtualStringTree to our data structure:

MyTree.VirtualTree := VST;

Then you can init your data tree with some values:

procedure TForm1.BuildStructure(Count: Integer);
var
  i, j: Integer;
  svNode, svNode2: TSVTreeNode<TMainData>;
  Data: TMainData;
begin
  MyTree.BeginUpdate;
  try
    for i := 0 to Count - 1 do
    begin
      Data.Name := Format('Root %D', [i]);
      Data.ID := i;
      svNode := MyTree.AddChild(nil, Data);
      for j:= 0 to 10 - 1 do
      begin
        Data.Name := Format('Child %D', [j]);
        Data.ID := j;
        svNode2 := MyTree.AddChild(svNode, Data);
      end;
    end;
  finally
    MyTree.EndUpdate;
  end;
end;

And set VST events to display your data:

procedure TForm1.vt1InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
  var ChildCount: Cardinal);
var
  svNode: TSVTreeNode<TMainData>;
begin
  svNode := MyTree.GetNode(Sender.GenerateIndex(Node));
  if Assigned(svNode) then
  begin
    ChildCount := svNode.FChildCount;
  end;
end;

procedure TForm1.vt1InitNode(Sender: TBaseVirtualTree; ParentNode,
  Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
var
  svNode: TSVTreeNode<TMainData>;
begin
  svNode := MyTree.GetNode(Sender.GenerateIndex(Node));
  if Assigned(svNode) then
  begin
    //if TSVTree<TTestas> is synced with Virtual Treeview and we are building tree by
    // setting RootNodeCount, then we must set svNode.FVirtualNode := Node to
    // have correct node references
    svNode.FVirtualNode := Node;  // Don't Forget!!!!
    if svNode.HasChildren then
    begin
      Include(InitialStates, ivsHasChildren);
    end;
  end;
end;

//display info how you like, I simply get name and ID values
procedure TForm1.vt1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
  svNode: TSVTreeNode<TMainData>;
begin
  svNode := MyTree.GetNode(Sender.GenerateIndex(Node));
  if Assigned(svNode) then
  begin
    CellText := Format('%S ID:%D',[svNode.FValue.Name, svNode.FValue.ID]);
  end;
end;

At this point you work only with your MyTree data structure and all the changes made to it will be reflected in your assigned VST. You then can always save (and load) underlying structure to stream or file. Hope this helps.

Sideway answered 19/3, 2011 at 23:10 Comment(4)
I dont see where I can download it? :)Frivolity
I just tested the difference between using the VT to store the data in, and your SVTreeby adding 1000 roots with 1000 children in each. Turns out that the SVTree uses around 100 megs more than the VT one, and the VT one is about twice as fast. Is it because we are using pointers and not the whole record in the VT?Frivolity
There will be some additional memory usage because TSVTreeNode objects are additionally created while building data structure. Don't know how you tested but building my data structure is a little bit slower because it needs to generate unique node's hash to be able to retrieve it later on VT events. I found it quite well performing in decent tests but if you need adding millions of nodes with huge level of hierarchy you may consider some other methods.Sideway
Yours is very nice and easy to use, and threadsafe aswell I presume? I will be using about 20.000 nodes maybe, however Memory usage is already a problem :PFrivolity
P
4

I believe you will be best served by finding an existing library containing a general tree implementation which you can then re-use to serve your needs.

To give you an idea why, here is some code I wrote to illustrate the most simple operation on the most simple tree structure imaginable.

type
  TNode = class
    Parent: TNode;
    NextSibling: TNode;
    FirstChild: TNode;
  end;

  TTree = class
    Root: TNode;
    function AddNode(Parent: TNode): TNode;
  end;

function TTree.AddNode(Parent: TNode);
var
  Node: TNode;
begin
  Result := TNode.Create;

  Result.Parent := Parent;
  Result.NextSibling := nil;
  Result.FirstChild := nil;

  //this may be the first node in the tree
  if not Assigned(Root) then begin
    Assert(not Assigned(Parent));
    Root := Result;
    exit;
  end;

  //this may be the first child of this parent
  if Assigned(Parent) and not Assigned(Parent.FirstChild) then begin
    Parent.FirstChild := Result;
  end;

  //find the previous sibling and assign its next sibling to the new node
  if Assigned(Parent) then begin
    Node := Parent.FirstChild;
  end else begin
    Node := Root;
  end;
  if Assigned(Node) then begin
    while Assigned(Node.NextSibling) do begin
      Node := Node.NextSibling;
    end;
    Node.NextSibling := Result;
  end;
end;

Note: I have not tested this code and so cannot vouch for its correctness. I expect it has defects.

All this does is add an new node to the tree. It gives you little control over where in the tree the node is added. If simply adds a new node as the last sibling of a specified parent node.

To take this sort of approach you would likely need to deal with:

  • Inserting after a specified sibling. Actually this is quite a simple variant of the above.
  • Removing a node. This is somewhat more complex.
  • Moving existing nodes within the tree.
  • Walking the tree.
  • Connecting the tree to your VST.

It's certainly feasible to do this, but you may be better advised to find a 3rd party library that already implements the functionality.

Paulsen answered 20/3, 2011 at 17:17 Comment(0)
G
2

If I understand correctly, you need a datastructure for your tree. Each individual node requires a record to hold its data. But the underlying heirarchy can be managed in a few different ways. Im guessing this is all to be managed in some sort of database - This has already been talked about on this site, so i will point you to:

Implementing a hierarchical data structure in a database

and here:

What is the most efficient/elegant way to parse a flat table into a tree?

and here:

SQL - How to store and navigate hierarchies?

Nested Set Model:

http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

Gorblimey answered 20/3, 2011 at 0:22 Comment(2)
The question has nothing to do with databases or flat files.Kristynkrock
It is a bit ambiguous - but he can see the principal of storing a tree structure in (some table/matrix/array etc) with these links.Gorblimey
M
0

If you are using recent versions of Delphi that supports Generics, check GenericTree

Mauretania answered 27/7, 2016 at 9:31 Comment(0)
M
-1

Delphi has generics nowadays. I just invented a very nice tree data structure. Not gonna give code away just yet, not really an open source person, maybe in the near future though, also other reasons see below.

But I will give some hints on how to re-create it:

Assuming all your nodes can contain the same data structure (which seems to be the case from above, a string, an id, and then links.

The ingredients you need to re-create this is the following:

  1. Generics
  2. A generic type T
  3. This type T needs to be constrained to class and constructor as follows:

<T : class, constructor> (In your case replace class with record, untested, but may also work)

  1. two fields: node array of self (hint hint), data : T;

  2. A property

  3. Not just any propery, a default property ;)

  4. A getter.

  5. A recursive constructor with depth and child.

  6. Some if statement to stop the construction.

  7. And ofcourse SetLength to create the links/nodes and calling some creates in a for loop and then some subtraction of something ;)

Given all of you enough hints, would be fun and interesting to see if anybody can re-create it, otherwise I might just as well patent it, just kidding, not gonna throw money against it, might expand the class though with other facilities.

The class allocates all nodes during construction like a true data structure... noting with add and remove and such, at least not for now.

Now comes the most interesting and funny aspect of this (secret) design, something I kinda wanted and is now a reality. I can now write code as follows:

TGroup is just an example can be anything as long as it's a class in my case. In this case it's just a class with mString

var
  mGroupTree : TTree<TGroup>;

procedure Main;
var
  Depth : integer;
  Childs : integer;
begin

  Depth := 2;
  Childs := 3;

  mGroupTree := TTree<TGroup>.Create( Depth, Childs );

  mGroupTree.Data.mString := 'Basket'; // notice how nice this root is ! ;)

  mGroupTree[0].Data.mString := 'Apples';
  mGroupTree[1].Data.mString := 'Oranges';
  mGroupTree[2].Data.mString := 'Bananas';

  mGroupTree[0][0].Data.mString := 'Bad apple';
  mGroupTree[0][1].Data.mString := 'Average apple';
  mGroupTree[0][2].Data.mString := 'Good apple';

  mGroupTree[1][0].Data.mString := 'Tiny orange';
  mGroupTree[1][1].Data.mString := 'Medium orange';
  mGroupTree[1][2].Data.mString := 'Big orange';

  mGroupTree[2][0].Data.mString := 'Straight banana';
  mGroupTree[2][1].Data.mString := 'Curved banana';
  mGroupTree[2][2].Data.mString := 'Crooked banana';

Now what you may notice from this actual test code is that it allows "array expansion" like I have rarely seen thanks to this property, which self-references sort of...

So [] [] is depth 2. [][][] would be depth 3.

I am still evaluating the use of this.

One potential problem is Delphi has no real technique to auto-expand these arrays, though none I have yet found and are statisfied with.

I would like a technique where I can write some code which can go to any depth level:

[0][0][0][0][0]

Not yet sure how to do that... simpelst option is "recursion".

real example:

procedure DisplayString( Depth : string; ParaTree : TTree<TGroup>);
var
  vIndex : integer;
begin
  if ParaTree <> nil then
  begin
//    if ParaTree.Data.mString <> '' then
    begin
      writeln( ParaTree.Data.mString );

      Depth := Depth + ' ';
      for vIndex := 0 to ParaTree.Childs-1 do
      begin
        DisplayString( Depth, ParaTree[vIndex] );
      end;
    end;
  end;
end;

Kinda interesting isn't it.

Still exploring it's usefullness for "real applications" and if I want to go with recursion or not ;)

Maybe some day I will open source all of my code. I am close to 40 years old, when I go beyond 40, from 39 to 40, I was kinda planning on going open source. Still 4 months away from 40 =D

(I must say this is the first time I am impressed by Generics, tested it long ago, it was super buggy back then and maybe design-wise unusable, but now with the bugs fixed and constrained generics, it's very impressive in latest Delphi Toyko 10.2.3 version august 2018 ! ;) :))

I am just scratching the surface of what is impossible with latest Delphi tech, maybe with anonymous methods writing recursive routines to process this data structure might become a bit easier, also maybe parallel processing might come into consideration, Delphi help mentions this for anonymous methods.

Bye, Skybuck.

Materialize answered 8/8, 2018 at 22:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.