Recent

Author Topic: search in TFPGObjectlist  (Read 2108 times)

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: search in TFPGObjectlist
« Reply #15 on: August 10, 2024, 01:56:56 pm »
I've never used AVL Tree before, and it's faster than FGL (at least with this solution)
I built up on your code (AVL tree myway) for curiosity. Here is my code. It add some randomization to the searched keys and writeln's the count of fit/no hits for minimal comparison of correct results.
Attached is my unit for "precision" timings uRDTSC), the windows way (works also probably on other i386/x86_64 Os'es.
Code: Pascal  [Select][+][-]
  1.   { TKeurmeesterList }
  2.  
  3. program pgmSearchLists;
  4.  
  5. {$mode objfpc}{$H+}
  6.  
  7. uses
  8.   Classes,
  9.   SysUtils,
  10.   fgl, uRdtsc,
  11.   StrUtils,
  12.   DateUtils,
  13.   AVL_Tree;
  14.  
  15. type
  16.   TKeurmeester = class
  17.     id: Integer;
  18.     naam: String;
  19.   end;
  20.  
  21.   { TKeurmeesterList }
  22.  
  23.   TKeurmeesterList = class(specialize TFPGObjectList<TKeurmeester>)
  24.   type
  25.     TIDMap = specialize TFPGMap<Integer, Integer>;
  26.   private
  27.     fIDMap: TIDMap;
  28.     fAVLTree: TAvlTree;
  29.     fAVLWorkObj: TKeurmeester;
  30.   public
  31.     constructor Create;
  32.     destructor Destroy; override;
  33.     function Add(aItem: TKeurmeester): Integer;
  34.     procedure Delete(aIndex: Integer);
  35.     function LocateKeurmeester(id: Integer): Boolean;
  36.     function LocateKeurmeesterIn(id: Integer): Boolean;
  37.     function LocateKeurmeesterMap(id: Integer): Boolean;
  38.     function LocateKeurmeesterAVL(id: Integer): Boolean;
  39.     function AvlTreeCompare(Tree: TAVLTree; Data1, Data2: Pointer): integer;
  40.     procedure BeginUpdate;
  41.     procedure EndUpdate;
  42.   end;
  43.  
  44. { TKeurmeesterList }
  45.  
  46. constructor TKeurmeesterList.Create;
  47. begin
  48.   inherited Create;
  49.   fIDMap := TIDMap.Create;
  50.   fIDMap.Duplicates := dupIgnore;
  51.   fIDMap.Sorted := True;
  52.   fAVLTree:= TAVLTree.CreateObjectCompare(@AvlTreeCompare);
  53.   fAVLWorkObj:=TKeurmeester.Create;
  54. end;
  55.  
  56. destructor TKeurmeesterList.Destroy;
  57. begin
  58.   fIDMap.Free;
  59.   fAVLTree.Free;
  60.   fAVLWorkObj.Free;
  61.   inherited Destroy;
  62. end;
  63.  
  64. function TKeurmeesterList.Add(aItem: TKeurmeester): Integer;
  65. begin
  66.   Result := inherited Add(aItem);
  67.   fIDMap.Add(aItem.id, Result);
  68.   fAVLTree.Add(aItem);
  69. end;
  70.  
  71. procedure TKeurmeesterList.Delete(aIndex: Integer);
  72. var
  73.   idx: Integer;
  74.   lNode: TAVLTreeNode;
  75. begin
  76.   idx := fIDMap.IndexOf(Items[aIndex].id);
  77.   if idx >= 0 then
  78.     fIDMap.Delete(idx);
  79.   if idx >= 0 then begin
  80.     lNode := fAVLTree.Find(Items[idx]);
  81.     if assigned(lNode) then
  82.       fAVLTree.Delete(lNode);
  83.   end;
  84.   inherited Delete(aIndex);
  85. end;
  86.  
  87. function TKeurmeesterList.LocateKeurmeester(id: Integer): Boolean;
  88. var
  89.   i: Integer;
  90. begin
  91.   Result := False;
  92.   for i := 0 to Count - 1 do
  93.   begin
  94.     if Items[i].id = id then
  95.     begin
  96.       Result := True;
  97.       break;
  98.     end;
  99.   end;
  100. end;
  101.  
  102. function TKeurmeesterList.LocateKeurmeesterIn(id: Integer): Boolean;
  103. var
  104.   ki: TKeurmeester;
  105. begin
  106.   Result := False;
  107.   for ki in Self do
  108.   begin
  109.     if ki.id = id then
  110.     begin
  111.       Result := True;
  112.       break;
  113.     end;
  114.   end;
  115. end;
  116.  
  117. function TKeurmeesterList.LocateKeurmeesterMap(id: Integer): Boolean;
  118. begin
  119.   Result := fIDMap.IndexOf(id) >= 0;
  120. end;
  121.  
  122. function TKeurmeesterList.LocateKeurmeesterAVL(id: Integer): Boolean;
  123. begin
  124.   fAVLWorkObj.id:=id;
  125.   Result := Assigned(fAVLTree.Find(fAVLWorkObj));
  126. end;
  127.  
  128. function TKeurmeesterList.AvlTreeCompare(Tree: TAVLTree; Data1, Data2: Pointer
  129.   ): integer;
  130. var
  131.   lData1: TKeurmeester  absolute Data1;
  132.   lData2: TKeurmeester  absolute Data2;
  133. begin
  134.   Result := lData1.id-lData2.id;
  135. end;
  136.  
  137. procedure TKeurmeesterList.BeginUpdate;
  138. begin
  139.   fIDMap.Sorted := False;
  140. end;
  141.  
  142. procedure TKeurmeesterList.EndUpdate;
  143. begin
  144.   fIDMap.Sort;
  145.   fIDMap.Sorted := True;
  146. end;
  147.  
  148. const
  149.   cNCount = 100000;   // Number of items
  150.   cRndCount = 512;    // List if random items to search  (mul of 2 for easy masking
  151. var
  152.   lTFAr: array[Boolean] of integer; // True false count
  153.   procedure ClearTFAr;
  154.   begin
  155.     lTFAr[False] := 0;
  156.     lTFAr[True] := 0;
  157.   end;
  158.  
  159. var
  160.   kl: TKeurmeesterList;
  161.   ki: TKeurmeester;
  162.   i, j, n, v, vl: Integer;
  163.   // valarr: Array [1..4] of Integer = (5378, 478315, 999998, 9999999);
  164.   valarr: Array [0..cRndCount-1] of Integer;
  165.   lIx: Integer;
  166.   dt: TDateTime;
  167.   lStart: Qword;
  168. begin
  169.   n := cNCount;
  170.   dt := Now;
  171.   //create list with data
  172.   kl := TKeurmeesterList.Create;
  173.   kl.BeginUpdate;
  174.   for i := 0 to n - 1 do
  175.   begin
  176.     ki := TKeurmeester.Create;
  177.     ki.id := i;
  178.     ki.naam := 'Item ' + IntToStr(i);
  179.     kl.Add(ki);
  180.   end;
  181.   kl.EndUpdate;
  182.   WriteLn('prepare data: ', MillisecondsBetween(Now, dt));
  183.   // Generate random values in valarr (~half below limit and half above }
  184.   for i:= Low(valarr) to High(valarr) do
  185.     valarr[i] := Random(n*3) div 2;
  186.  
  187.   for j := 1 to 4 do
  188.   begin
  189.     v := (j * cNCount) div 4;
  190.     WriteLn('==========================');
  191.     WriteLn('Check random IDs for nbitems = ',  v);
  192.     WriteLn('--------------------------');
  193.     //"for in" test
  194.     ClearTFAr;
  195.     lStart := CPUTickStamp;
  196.     dt := Now;
  197.     for i := 0 to v do begin
  198.       lIx := i and (cRndCount - 1);
  199.       inc(lTFAr[kl.LocateKeurmeesterIn(valarr[lIx])]);
  200.     end;
  201.     WriteLn('"for in" loop time in ms: ', MillisecondsBetween(Now, dt),
  202.            '; ', RdtscElapsed(lStart, CPUTickStamp),
  203.            Format('; result: True:%d  False:%d', [lTFAr[True], lTFAr[False]]));
  204.     //"for to do" test
  205.     ClearTFAr;
  206.     lStart := CPUTickStamp;
  207.     dt := Now;
  208.     for i := 0 to v do begin
  209.       lIx := i and (cRndCount - 1);
  210.       inc(lTFAr[kl.LocateKeurmeester(valarr[lIx])]);
  211.     end;
  212.     WriteLn('"for to do" loop time in ms: ', MillisecondsBetween(Now, dt),
  213.       '; ', RdtscElapsed(lStart, CPUTickStamp),
  214.       Format('; result: True:%d  False:%d', [lTFAr[True], lTFAr[False]]));
  215.     //map test
  216.     ClearTFAr;
  217.     lStart := CPUTickStamp;
  218.     dt := Now;
  219.     for i := 0 to v do begin
  220.       lIx := i and (cRndCount - 1);
  221.       inc(lTFAr[kl.LocateKeurmeesterMap(valarr[lIx])]);
  222.     end;
  223.     WriteLn('map time in ms: ', MillisecondsBetween(Now, dt),
  224.       '; ', RdtscElapsed(lStart, CPUTickStamp),
  225.       Format('; result: True:%d  False:%d', [lTFAr[True], lTFAr[False]]));
  226.     //AVLTree test
  227.     ClearTFAr;
  228.     lStart := CPUTickStamp;
  229.     dt := Now;
  230.     for i := 0 to v do begin
  231.       lIx := i and (cRndCount - 1);
  232.       Inc(lTFAr[kl.LocateKeurmeesterAVL(valarr[lIx])]);
  233.     end;
  234.     WriteLn('AVL time in ms: ', MillisecondsBetween(Now, dt),
  235.       '; ', RdtscElapsed(lStart, CPUTickStamp),
  236.       Format('; result: True:%d  False:%d', [lTFAr[True], lTFAr[False]]));
  237.   end;
  238.   kl.Free;
  239.   ReadLn;
  240. end.
I love AVL tree. This one works perfectly and allows quite a few interesting extensions.


Thaddy

  • Hero Member
  • *****
  • Posts: 15747
  • Censorship about opinions does not belong here.
Re: search in TFPGObjectlist
« Reply #16 on: August 10, 2024, 02:11:14 pm »
Or alternatively simply use generics.collections.TObjectList<T> instead of fgl.
If I smell bad code it usually is bad code and that includes my own code.

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: search in TFPGObjectlist
« Reply #17 on: August 10, 2024, 02:18:55 pm »
Or alternatively simply use generics.collections.TObjectList<T> instead of fgl.
Just show us your code using  generics.collections.TObjectList<T>.

Thanks.

jamie

  • Hero Member
  • *****
  • Posts: 6591
Re: search in TFPGObjectlist
« Reply #18 on: August 10, 2024, 04:01:08 pm »
you can do a binary search with the objectlist, but you first need to issue the sort prior to if you have added any items since the last time.

 The LIST^ property gives you the pointer to the whole list in a linear state and you then can start in the middle, work your way around dividing by two the index until you find it.

 I can code up something if you wish, but the sort function must be called after adding items before performing this bin search.
The only true wisdom is knowing you know nothing

Thaddy

  • Hero Member
  • *****
  • Posts: 15747
  • Censorship about opinions does not belong here.
Re: search in TFPGObjectlist
« Reply #19 on: August 10, 2024, 07:30:18 pm »
nnnnnnnno, again, you are not in your best form lately:
The TObjectList<t> from generics.collections WILL use a sort under the hood. Defaults to quicksort, but you can even specify the sort.
If I smell bad code it usually is bad code and that includes my own code.

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: search in TFPGObjectlist
« Reply #20 on: August 10, 2024, 07:58:42 pm »
nnnnnnnno, again, you are not in your best form lately:
The TObjectList<t> from generics.collections WILL use a sort under the hood. Defaults to quicksort, but you can even specify the sort.
As usual,you are absolutly unable to show better functional code.

Stay with the scandalized Sher participant on this forum. That is out !

Thaddy

  • Hero Member
  • *****
  • Posts: 15747
  • Censorship about opinions does not belong here.
Re: search in TFPGObjectlist
« Reply #21 on: August 10, 2024, 08:05:41 pm »
No, you are too lazy to inspect generics.collections.TobjectList <T>.
You have the code.. Silly answer. Shut up.
generics.collections.TobjectList<T> uses a binary search when sorted and a linear search when it is not sorted. And that is out of the box. Shut up. You do not know nor want to know what you are talking about.
It is the code, look at the code... Frankly I suppose you are not even capable of understanding that code. Period.
« Last Edit: August 10, 2024, 08:15:35 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: search in TFPGObjectlist
« Reply #22 on: August 10, 2024, 08:23:26 pm »
No, you are too lazy to inspect generics.collections.TobjectList <T>.
You have the code.. Silly answer. Shut up.
generics.collections.TobjectList<T> uses a binary search when sorted and a linear search when it is not sorted. And that is out of the box. Shut up. You do not know nor want to know what you are talking about.
It is the code, look at the code... Frankly I suppose you are not even capable of understanding that code. Period.
Stilo bragging, no show. :-)))

Thaddy

  • Hero Member
  • *****
  • Posts: 15747
  • Censorship about opinions does not belong here.
Re: search in TFPGObjectlist
« Reply #23 on: August 10, 2024, 08:45:09 pm »
Why would I? You pretend you know, do it yourself.
(But I will provide an example later, but not for you. The license is free for everybody except BrunoK, who is not licensed)
If I smell bad code it usually is bad code and that includes my own code.

BrunoK

  • Hero Member
  • *****
  • Posts: 589
  • Retired programmer
Re: search in TFPGObjectlist
« Reply #24 on: August 10, 2024, 08:52:47 pm »
Why would I? You pretend you know, do it yourself.
Simply because you are just pretending but are actually a no show bragging guy ;-)))))

Thaddy

  • Hero Member
  • *****
  • Posts: 15747
  • Censorship about opinions does not belong here.
Re: search in TFPGObjectlist
« Reply #25 on: August 10, 2024, 09:37:47 pm »
Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. uses generics.collections;
  3. type
  4.   Tsome=TSortedList<integer>;
  5. var
  6.   l:Tsome;
  7.   I:integer;
  8. begin
  9.   l := Tsome.create;
  10.   { l.sorted :=true; }
  11.   for i := 0 to 1000000 do
  12.     l.add(i+5);
  13.   writeln(l.indexof(400000));// binary search used
  14.   l.free;
  15. end.
« Last Edit: August 10, 2024, 09:42:17 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

paweld

  • Hero Member
  • *****
  • Posts: 1220
Re: search in TFPGObjectlist
« Reply #26 on: August 11, 2024, 08:51:58 am »
Unfortunately, BinarySearch won't work in the case given by TS, because BinarySearch requires exactly the class you want to find that is in the list, and TS searches based on data received from another source (it creates a class based on that data, but it is a NEW class, so BinarySearch won't find it - same situation as with TFPGObjectList.IndexOf).


The execution time of BianrySearch it looks similar (a little slower, but not much) to FGL with a map.


The code I've tested:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Classes, SysUtils, fgl, DateUtils, StrUtils, avl_tree, Generics.Collections, Generics.Defaults;
  7.  
  8. type
  9.   TKeurmeester = class
  10.     id: Integer;
  11.     naam: String;
  12.   end;
  13.  
  14.   { TKeurmeesterList }
  15.  
  16.   TKeurmeesterList = class(specialize TFPGObjectList<TKeurmeester>)
  17.   type
  18.     TIDMap = specialize TFPGMap<Integer, Integer>;
  19.   private
  20.     fIDMap: TIDMap;
  21.   public
  22.     constructor Create;
  23.     destructor Destroy; override;
  24.     function Add(aItem: TKeurmeester): Integer;
  25.     procedure Delete(aIndex: Integer);
  26.     function LocateKeurmeesterMap(id: Integer):  Boolean;
  27.     procedure BeginUpdate;
  28.     procedure EndUpdate;
  29.   end;
  30.  
  31.   { TKeurmeesterListGC }
  32.  
  33.   TKeurmeesterListGC = class(specialize TObjectList<TKeurmeester>)
  34.   public
  35.     function LocateKeurmeester(id: Integer):  Boolean;
  36.   end;
  37.  
  38. { TKeurmeesterListGC }
  39.  
  40. function TKeurmeesterListGC.LocateKeurmeester(id: Integer): Boolean;
  41. var
  42.   idx: Integer;
  43.   ki: TKeurmeester;
  44. begin
  45.   ki := TKeurmeester.Create;
  46.   ki.id := id;
  47.   Result := Self.BinarySearch(ki, idx);
  48.   ki.Free;
  49. end;
  50.  
  51. { TKeurmeesterList }
  52.  
  53. constructor TKeurmeesterList.Create;
  54. begin
  55.   inherited Create;
  56.   fIDMap := TIDMap.Create;
  57.   fIDMap.Duplicates := dupIgnore;
  58.   fIDMap.Sorted := True;
  59. end;
  60.  
  61. destructor TKeurmeesterList.Destroy;
  62. begin
  63.   fIDMap.Free;
  64.   inherited Destroy;
  65. end;
  66.  
  67. function TKeurmeesterList.Add(aItem: TKeurmeester): Integer;
  68. begin
  69.   Result := inherited Add(aItem);
  70.   fIDMap.Add(aItem.id, Result);
  71. end;
  72.  
  73. procedure TKeurmeesterList.Delete(aIndex: Integer);
  74. var
  75.   idx: Integer;
  76. begin
  77.   idx := fIDMap.IndexOf(Items[aIndex].id);
  78.   if idx >= 0 then
  79.     fIDMap.Delete(idx);
  80.   inherited Delete(aIndex);
  81. end;
  82.  
  83. function TKeurmeesterList.LocateKeurmeesterMap(id: Integer): Boolean;
  84. begin
  85.   Result := fIDMap.IndexOf(id) >= 0;
  86. end;
  87.  
  88. procedure TKeurmeesterList.BeginUpdate;
  89. begin
  90.   fIDMap.Sorted := False;
  91. end;
  92.  
  93. procedure TKeurmeesterList.EndUpdate;
  94. begin
  95.   fIDMap.Sort;
  96.   fIDMap.Sorted := True;
  97. end;
  98.  
  99. function CompareAVL(Data1, Data2: Pointer): Integer;
  100. begin
  101.   Result := TKeurmeester(Data1).id - TKeurmeester(Data2).id;
  102. end;
  103.  
  104. function CompareGC(const Left, Right: TKeurmeester): Integer;
  105. begin
  106.   Result := TCompare.Integer(Left.id, Right.id);
  107. end;
  108.  
  109. var
  110.   kl: TKeurmeesterList;
  111.   ki: TKeurmeester;
  112.   i, j, n, v: Integer;
  113.   valarr: Array [1..4] of Integer = (5378, 478315, 999998, 99999999);
  114.   dt: TDateTime;
  115.   tree: TAVLTree;
  116.   klgc: TKeurmeesterListGC;
  117. begin
  118.   n := 10000000;
  119.   //FGL
  120.   //create list with data
  121.   dt := Now;
  122.   kl := TKeurmeesterList.Create;
  123.   kl.BeginUpdate;
  124.   for i := 0 to 9999999 do
  125.   begin
  126.     ki := TKeurmeester.Create;
  127.     ki.id := i;
  128.     ki.naam := 'Item ' + IntToStr(i);
  129.     kl.Add(ki);
  130.   end;
  131.   kl.EndUpdate;
  132.   WriteLn('FGL prepare data: ', MillisecondsBetween(Now, dt));
  133.   for j := Low(valarr) to High(valarr) do
  134.   begin
  135.     WriteLn('==========================');
  136.     WriteLn('Check ID: ', valarr[j], ' loop count: ', n);
  137.     WriteLn('--------------------------');
  138.     //map test
  139.     dt := Now;
  140.     for i := 0 to n do
  141.       kl.LocateKeurmeesterMap(valarr[j]);
  142.     WriteLn('map time in ms: ', MillisecondsBetween(Now, dt), '; result: ', IfThen(kl.LocateKeurmeesterMap(valarr[j]), 'True', 'False'));
  143.   end;
  144.   kl.Free;
  145.   //AVL
  146.   //create tree with data
  147.   dt := Now;
  148.   tree := TAVLTree.Create(@CompareAVL);
  149.   for i := 0 to 9999999 do
  150.   begin
  151.     ki := TKeurmeester.Create;
  152.     ki.id := i;
  153.     ki.naam := 'Item ' + IntToStr(i);
  154.     tree.Add(ki);
  155.   end;
  156.   WriteLn('AVL prepare data: ', MillisecondsBetween(Now, dt));
  157.   for j := Low(valarr) to High(valarr) do
  158.   begin
  159.     WriteLn('==========================');
  160.     WriteLn('Check ID: ', valarr[j], ' loop count: ', n);
  161.     WriteLn('--------------------------');
  162.     //avl test
  163.     dt := Now;
  164.     ki := TKeurmeester.Create;
  165.     ki.id := valarr[j];
  166.     for i := 0 to n do
  167.       tree.Find(ki);
  168.     WriteLn('avl time in ms: ', MillisecondsBetween(Now, dt), '; result: ', IfThen(tree.Find(ki) <> nil, 'True', 'False'));
  169.     ki.Free;
  170.   end;
  171.   tree.Free;
  172.   //generics.collection
  173.   //create list with data
  174.   dt := Now;
  175.   klgc := TKeurmeesterListGC.Create;
  176.   for i := 0 to 9999999 do
  177.   begin
  178.     ki := TKeurmeester.Create;
  179.     ki.id := i;
  180.     ki.naam := 'Item ' + IntToStr(i);
  181.     klgc.Add(ki);
  182.   end;
  183.   klgc.Sort(specialize TComparer<TKeurmeester>.Construct(@CompareGC));
  184.   WriteLn('GC prepare data: ', MillisecondsBetween(Now, dt));
  185.   for j := Low(valarr) to High(valarr) do
  186.   begin
  187.     WriteLn('==========================');
  188.     WriteLn('Check ID: ', valarr[j], ' loop count: ', n);
  189.     WriteLn('--------------------------');
  190.     //binarysearch test
  191.     dt := Now;
  192.     for i := 0 to n do
  193.       klgc.LocateKeurmeester(valarr[j]);
  194.     WriteLn('binarysearch time in ms: ', MillisecondsBetween(Now, dt), '; result: ', IfThen(klgc.LocateKeurmeester(valarr[j]), 'True', 'False'));
  195.   end;
  196.   klgc.Free;
  197.   ReadLn;
  198. end.
Best regards / Pozdrawiam
paweld

Thaddy

  • Hero Member
  • *****
  • Posts: 15747
  • Censorship about opinions does not belong here.
Re: search in TFPGObjectlist
« Reply #27 on: August 11, 2024, 09:02:40 am »
@paweld,
I overlooked that, you are right.
If I smell bad code it usually is bad code and that includes my own code.

JohnKuiper

  • New member
  • *
  • Posts: 7
Re: search in TFPGObjectlist
« Reply #28 on: August 12, 2024, 10:21:10 am »
My problem on using system.generics is {$mode delphi}.  My application is build on {$mode objfpc}.

@paweld
TFPGMap is nice, bu I want to do it simple. Just look if the value still exists.
Code: [Select]
procedure TKeurmeesterUitslag.GetKeurmeesters;
var
  Row             : TKMUitslag;
  KeurmeesterItem : TKeurmeester;
begin
  fKeurmeester.Clear;
  for Row in fLijst do
  begin
    KeurmeesterItem      := TKeurmeester.create;
    KeurmeesterItem.id   := row.keurmeester_id;
    KeurmeesterItem.naam := row.keurmeester;
    if fKeurmeesterlijst.Indexof(keurmeesterItem) = -1 then
      fKeurmeesterlijst.Add(keurmeesterItem)
    else
      KeurmeesterItem.free
    end;
  end;
end;
If I analyze this then it tells:

Quote
1 search for en item in flijst
2 create an object
3 put the two variabeles into the object
4 search in the fKeurmeesterlijst
5 if it isn't, put the object into the fKeurmeesterlijst
But option 2 has a new pointer value. Indexof can't find this object values, so it add the object.

Tell my if I'm wrong.

TRon

  • Hero Member
  • *****
  • Posts: 3302
Re: search in TFPGObjectlist
« Reply #29 on: August 12, 2024, 10:43:52 am »
But option 2 has a new pointer value. Indexof can't find this object values, so it add the object.
Not being paweld: That is correct. But I haven't seen this specific solution being posted in this thread (I might have overlooked)

Isn't this a candidate for a collection in order to keep it simple ?
This tagline is powered by AI

 

TinyPortal © 2005-2018