Problem with TFPGObjectList lazarus / 62-General ---------------------------------------------------------------------- HappyLarry · 2016-07-28 09:44 I am trying to use TFPGObjectList but I get a SIGSEGV error which occurs when at the line  A.Add(B); and I cant see why. The program just adds a single object ('Lazarus',28,7)  to an empty list. Any ideas gratefully received. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;uses  sysutils, fgl; type    TItem = class      s:string;    p:integer;      q:integer;      procedure SetItem(f1:string;f2:integer;f3:integer);    end;     TObjectList = specialize TFPGObjectList;     procedure TItem.SetItem(f1:string;f2:integer;f3:integer);    begin       s:=f1;       p:=f2;       q:=f3;    end;  var  A:TObjectList;  B:TItem; procedure ShowObjectList(Z:TObjectList);var  k:integer;begin   For k:= 0 to Z.count-1 do   begin      writeln(k:4,  Z[k].s:6,   Z[k].p:4, Z[k].q:4);   end;   writeln;end;  begin  writeln('TFPGObjectList');   A:=TObjectList.create;   B:=TItem.create;  B.SetItem('Lazarus',28,7);   A.Add(B);   ShowObjectList(A);  writeln(A.Count);   B.free;  A.free;   writeln(' ---done----');  readln;end. ---------------------------------------------------------------------- howardpc · 2016-07-28 10:06 Either remove the   B.Free; or after its creation set   A.FreeObjects:=False; ---------------------------------------------------------------------- Leledumbo · 2016-07-28 10:49 Quote from: howardpc on July 28, 2016, 12:06:43 pmEither remove the   B.Free; or after its creation set   A.FreeObjects:=False; Or call Create with parameter false. ---------------------------------------------------------------------- Thaddy · 2016-07-28 10:54 @Leledumbo: Indeed, that is the better solution, because the programmer can express intend over default behavior that may not be known to him. As is the case here. ---------------------------------------------------------------------- HappyLarry · 2016-07-28 11:07 Both    A.FreeObjects:=False; and      A:=TObjectList.create(free); prevent the SIGSEG.  However if I try to add a second item then the second overwrites the first in the list. For instance in the code below Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   A.FreeObjects:=False;   B.SetItem('Lazarus',28,7);  A.Add(B);  ShowObjectList(A);  writeln(A.Count);    B.SetItem('Free Pascal',15,9);  A.Add(B);   ShowObjectList(A);  writeln(A.Count); the output is Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TFPGObjectList   0Lazarus  28   7 1   0Free Pascal  15   9   1Free Pascal  15   9 2---done----  How might I prevent this? ---------------------------------------------------------------------- Blaazen · 2016-07-28 11:30 Because you didn't create a new object. You are operating (SetItem) with the same item and you inserted it twice to the list (i.e. objectlist contains two references to the same object). ---------------------------------------------------------------------- HappyLarry · 2016-07-28 12:40 @Blaazen Thanks What is the best way of creating a List of 1000 objects using TFPGObjectList? Do I have to create an array of them first? (With TFPGList you add the items in turn to the list as I have here, but that obviously doesn't work with TFPGObjectList). ---------------------------------------------------------------------- sfeinst · 2016-07-28 13:30 If you are hardcoding everything, just use a For loop.  Inside the for loop use B := TItem.Create; B.SetItem(..whatever data you want..); A.Add(B); The problem you are having is you only create once.  You have to create every time. ---------------------------------------------------------------------- HappyLarry · 2016-07-28 22:48 Thanks I can now create a list. I am trying to search it with Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   B:=TItem.create;  B.SetItem('Lazarus',3,7);  writeln(A.IndexOf(B)); The result is -1 which means (Lazarus 3,7) can't be found, whereas the answer should be 1 (It ends up in the second position).. To check I added Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   If B=A.Items[1] then     writeln('Equal')  else      writeln('Not equal'); and got the answer 'Not equal' Any ideas? Full code Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;uses  sysutils, fgl; type    TItem = class      s:string;    p:integer;      q:integer;      procedure SetItem(f1:string;f2:integer;f3:integer);      procedure ShowItem;    end;     TObjectList = specialize TFPGObjectList;     procedure TItem.SetItem(f1:string;f2:integer;f3:integer);    begin       s:=f1;       p:=f2;       q:=f3;    end;     procedure TItem.ShowItem;    begin       writeln(s:12,   p:4,  q:4);    end;  var  A:TObjectList;  B:TItem; procedure ShowTitle(Message:string);begin     writeln;     writeln(Message);     writeln('---------------');end; procedure ShowObjectList(Z:TObjectList);var  k:integer;begin   For k:= 0 to Z.count-1 do   begin      writeln(k:4,  Z[k].s:12,   Z[k].p:4, Z[k].q:4);   end;   writeln;end; function compare1(const a, b: TItem): Integer;begin  If a.s > b.s then     Result := 1;  If a.s = b.s then   Result := 0;  If a.s < b.s then     Result := -1;end; function compare2(const a, b: TItem): Integer;begin  Result := a.p - b.p;end; function compare3(const a, b: TItem): Integer;begin  Result := a.q - b.q;end;  begin  ShowTitle('TFPGObjectList');   A:=TObjectList.create;  A.FreeObjects:=False;   ShowTitle('Adding objects');   B:=TItem.create;  B.SetItem('Lazarus',3,7);  A.Add(B);   B:=TItem.create;  B.SetItem('Python',8,5);  A.Add(B);   B:=TItem.create;  B.SetItem('Free Pascal',3,10);  A.Add(B);   B:=TItem.create;  B.SetItem('Visual Basic',5,11);  A.Add(B);  writeln('Index of B is ',A.IndexOf(B));   ShowTitle('Sort by column 1');  A.Sort(@Compare1);  ShowObjectList(A);  writeln(A.Count);   ShowTitle('Sort by column 2');  A.Sort(@Compare2);  ShowObjectList(A);  writeln(A.Count);   ShowTitle('Sort by column 3');  A.Sort(@Compare3);  ShowObjectList(A);  writeln(A.Count);   B:=TItem.create;  B.SetItem('Lazarus',3,7);  writeln(A.IndexOf(B));   If B=A.Items[1] then     writeln('Equal')  else      writeln('Not equal');   B.free;  A.free;   writeln('---done----');  readln;end. ---------------------------------------------------------------------- molly · 2016-07-28 23:00 Quote from: HappyLarry on July 29, 2016, 12:48:09 amAny ideas? They are two separate objects as you created two of them (containing the same field values, i give you that) , as such they are not the same. Hence the answer of -1 (or not equal) you got. ---------------------------------------------------------------------- HappyLarry · 2016-07-28 23:04 Fair point, but how can you create a TItem object in order to search the list using A.IndexOf(T:TItem) otherwise? ---------------------------------------------------------------------- molly · 2016-07-28 23:56 Quote from: HappyLarry on July 29, 2016, 01:04:58 am..., but how can you create a TItem object in order to search the list using A.IndexOf(T:TItem) otherwise? You can't, period. Each item (=object/class) that you create is an individual item, that has no association with all the other items that you have stored in the list (or any other class item that you have created outside that list). The way to use (a specialized) TObjectList is by creating those individual items, store them and parse the list in order to 'find' an item. In case you'd like to use indexOf you would store the pointer to that particular item into a variable so that you can use that later on. I think that what you're actually looking for is a so-called associative list, e.g. a list which can store items for you but that are associated with a (unique) number or string. For simple cases you can use TStringList for that, as it is also capable of storing objects. But, since you are already trying to solve things with generics, you would be actually looking for a so called dictionary list. In such a list you can store items and associate each item stored with a string or other value. But, i believe fpc has no dictionary class of it's own ? You might be able to find something here  or perhaps some-one around here as a link to a generics collection that might be able to help you out. If a dictionary is not what you seek then the only other option that could perhaps be viable is to adjust the objectlist to your likings , by for example overriding the indexof method or by adding helpers that allow you to search the list as you would like (on field names). edit: PS: found a thread here with a link to here. ---------------------------------------------------------------------- shobits1 · 2016-07-29 03:37 or you could create a function that return the index of item,, something like this : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function GetItemIndex(AList: TObjectList; AstrS: string; AintP, AintQ : Integer): Integer;var  i: Integer;  item: TItem;begin  result := -1;  for i := 0 to Pred(AList.Count) do  begin     item := AList[i];     if (item.p <> AintP) or (item.q <> AintQ) then        Continue;      // use CompareStr if you want case sensitivity     if CompareText(item.s, AstrS)=0 then        Exit(i);  end;end; // if you wish to pass TItem directly.function GetItemIndex(AList: TObjectList; AItem: TItem): Integer;begin   Result := GetItemIndex( AList, AItem.s, AItem.p, AItem.q);end; bear in mind that this is not the most effective way but it works  . ---------------------------------------------------------------------- Thaddy · 2016-07-29 05:50 Quote from: molly on July 29, 2016, 01:56:41 amBut, i believe fpc has no dictionary class of it's own ? In the FGL there is for example TFPGMap which has dictionary semantics. It even has a map for reference counted objects:TFPGMapInterfacedObjectData. And it has fast search capabilities. There is also THashMap in FCL-STL, which has also TDictionary semantics. Both are a TDictionary implementation in all but name. So if you want a dictionary (which is the same as a map) you can do: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses fgl;type  TDictionary  = class(TFPGMap);// or alternativelyuses ghashmap;type  TDictionary = class(THashMap);// or alternatively non-generic simply:uses contnrs; TDictionary = class(TFPObjectHashTable);  Hey! Presto! TDictionary Because a map = dictionary = table!  in the context of data structure theory. Mathematically map is the correct name, btw. The first is faster with inserts, the second is faster with searches. There's also the sparta generics library of course that I prefer, but is not (yet?) in the distribution. ---------------------------------------------------------------------- molly · 2016-07-29 07:19 Thanks Thaddy, I read your intial post which got me searching on the: why on earth i missed that. Seems i shamefully overlooked the maps  The edited post is even nicer. Thank you for that.  Now, let's see what OP has in mind while i go toying with what you posted. ---------------------------------------------------------------------- Thaddy · 2016-07-29 08:16 Here's a possible solution for OP given Molly's tip: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;{$mode delphi}uses  fgl; type  TItem = record    p:integer;  q:integer;    function SetItem(f2:integer;f3:integer):TItem;  end;    TDictionary  = class(TFPGMap);    function TItem.SetItem(f2:integer;f3:integer):Titem;  begin    p:=f2;    q:=f3;    Result := self;  end;     procedure ShowObjectList(Z:TDictionary);  var    k:integer;  begin    For k:= 0 to Z.count-1 do      writeln(Z.Keys[k] :6, Z.Data[k].p :4, Z.Data[k].q :4);    writeln;  end; var  A:TDictionary;  B:TItem; begin  A:=TDictionary.Create;  try    A.Add('Lazarus',B.SetItem(28,7));     A.Add('Freepascal',B.SetItem(300,311));    ShowObjectList(A);    writeln(A.Count);  finally    A.free;  end;  writeln('---done----');  readln;end.  Note I used a record instead of a class and a function - that returns self - instead of a procedure. That enables very powerful notation. ---------------------------------------------------------------------- HappyLarry · 2016-07-29 12:07 Plenty to look at here! When I posted this originally, I was trying to find a Free Pascal unit that offered me built-in data structures and methods to create an array of records (table), where I could add, amend and delete entries and (preferably) search on any field and sort on any field. This is a fairly common task. @mollly I think you have shown that TFPGObjectList is not the way to go! 1. Sorting is good because the lis can be easily sorted by each field, 2. Search possibilities using IndexOf are not good without extra work such as the search function suggested by Thaddy. I looked at StringLists with 'AddObject' but I have not managed to get that working. @Thaddy Your code with TFPGMap instead was interesting. I used similar code with a simple record structure (not iDelphi mode so no Record + function) which resulted in less object-oriented code but still reasonably easy to use. In this case 1. It was easy to sort the dictionary on the key field. 2. There were no methods to sort the dictionary on non-key fields. Although there is a compare function, the sort method doesn't allow it to be used. 3. Searching the key field is easy 4. Searching an individual  non-key fields is not possible. Searching for the whole TItem is possible. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {1. You can search easily on the key,2. You can search on the (whole) data for a key but not a single field3. You can sort on the key4. you can't sort on the data fields} //The Dictionary is a List of entries//Each entry consists of Key + Item program project1;uses  sysutils, fgl; type    TItem = record      p:integer;      q:integer;    end;     TDictionary = specialize TFPGMap; var  A:TDictionary;  B:TItem;  x:integer; procedure ShowTitle(Message:string);begin     writeln;     writeln(Message);     writeln('---------------');end; procedure SetItem(var Item:TItem; f2:integer;f3:integer);begin   With Item do   begin     p:=f2;     q:=f3;   end;end; procedure ShowEntryFromKey(S:string; Z:TDictionary);begin   writeln(S:12, z.Data[Z.IndexOf(S)].p:4, z.Data[Z.IndexOf(S)].q:4);end; procedure ShowEntryFromIndex(k:integer; Z:TDictionary);begin   writeln(z.Keys[k]:12, z.Data[k].p:4, Z.Data[k].q:4);end; procedure ShowDictionary(Z:TDictionary);var  k:integer;begin   For k:= 0 to Z.count-1 do   begin      writeln(k:4, z.Keys[k]:12, z.Data[k].p:4, Z.Data[k].q:4);   end;   writeln;end; begin  ShowTitle('TFPGObjectList');   ShowTitle('Adding items');  A:=TDictionary.create;  SetItem(B,3,7);  A.Add('Lazarus', B);   SetItem(B,8,5);  A.Add('Python',B);   SetItem(B,3,10);  A.Add('Free Pascal',B);   SetItem(B,5,11);  A.Add('Visual Basic',B);   ShowTitle('List of itens');  ShowDictionary(A);   A.Sort;  ShowTitle('Sorted list of items') ;  ShowDictionary(A);   ShowTitle('Search for a key');  If A.Find('Lazarus',x) then  begin    ShowEntryFromKey('Lazarus',A);  end;   ShowTitle('Search for an index');  ShowEntryFromIndex(2,A);   ShowTitle('Search for a key (alternative)');  A.Find('Visual Basic',x);  ShowEntryFromIndex(x,A);   ShowTitle('Search column 2 for 8,5');  SetItem(B,8,5);  ShowEntryFromIndex(A.IndexOfData(B), A);   A.free;  writeln('---done----');  readln;end. As you say,  GHashSet will concentrate on speedy searching rather than sorting. The obvious possiblity would be TFPGList. This works well or a list of integers or strings (although the search is a linear search and quite slow for long lists). I tried using use it with records of several fields but I was unsuccessful. I get the error  Error: Operator is not overloaded: "TItem" = "TItem" Here is my code. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;uses  sysutils, fgl; type    TItem = record      s:string;    p:integer;      q:integer;    end;     TItemList = specialize TFPGList; var  A:TItemList;  B:TItem;  begin   readln;end. Any further observations or suggestions are welcome. Thanks to all contributors so far. ---------------------------------------------------------------------- hnb · 2016-07-29 12:34 Quote from: HappyLarry on July 29, 2016, 02:07:16 pm...  Error: Operator is not overloaded: "TItem" = "TItem" ... To solve that you have 2 options: override operator "=" (by class operator)try to use more user friendly generic library: Generics.Collections (compatible with Delphi) ---------------------------------------------------------------------- Thaddy · 2016-07-29 12:42 Quote from: hnb on July 29, 2016, 02:34:53 pmQuote from: HappyLarry on July 29, 2016, 02:07:16 pm...  Error: Operator is not overloaded: "TItem" = "TItem" ... To solve that you have 2 options: override operator "=" (by class operator)try to use more user friendly generic library: Generics.Collections (compatible with Delphi) The choice for naming the record Titem is unfortunate. ---------------------------------------------------------------------- howardpc · 2016-07-29 12:46 Quote from: HappyLarry on July 29, 2016, 02:07:16 pmWhen I posted this originally, I was trying to find a Free Pascal unit that offered me built-in data structures and methods to create an array of records (table), where I could add, amend and delete entries and (preferably) search on any field and sort on any field. This is a fairly common task. Obviously there is the db unit, and descendants of TDataset such as TBufDataset. Presumably you are looking for an object-oriented solution? ---------------------------------------------------------------------- Thaddy · 2016-07-29 13:04 If that is indeed the case I can recommend TBufDataset. It is like a pretty complete mini database. very well suited for single tables. Here's a very simple example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program bufdbtest;{$apptype console}{$mode objfpc}uses  db,BufDataset;var  BufDb:TBufDataset;begin BufDb:=TBufDataset.Create(nil); try   BufDb.FieldDefs.Add('NAME',ftString,20);   BufDb.FieldDefs.Add('NUM',ftinteger);   BufDb.FieldDefs.Add('NUM2',ftInteger);   BufDb.CreateDataSet;   BufDb.Open;   BufDb.Append;   BufDb.FieldByName('NAME').Value:='Free';   BufDb.Post;   BufDb.Append;   BufDb.FieldByName('NAME').Value:='Pascal';   BufDb.Post;   BufDb.SaveToFile('BufDb.txt'); finally   BufDb.Close;   BufDb.Free; end; // now, open.. BufDb := TBufDataset.Create(nil); try   BufDb.LoadFromFile('BufDb.txt');   BufDb.Open;   BufDb.First;   Writeln(BufDb.FieldByName('NAME').Value); finally   BufDb.Close;   BufDb.Free; end; end. ---------------------------------------------------------------------- shobits1 · 2016-07-29 13:55 Quote from: Thaddy on July 29, 2016, 03:04:37 pmIf that is indeed the case I can recommend TBufDataset. It is like a pretty complete mini database. very well suited for single tables. Exactly my thoughts,, using TBufDataset will simplify things a lot,, but keep in mind there is no IndexOf function here (although you can add an the index as field), if you don't like Dataset approach you can use class helper like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i    // Adding this to your code, will change the behavior of IndexOf function    TObjectListHelper = class helper for TObjectList      function IndexOf(AItem: TItem): Integer; overload;    end;     function TObjectListHelper.IndexOf(AItem: TItem) : Integer; overload;    var      i: Integer;      item: TItem;    begin     result := -1;   for i := 0 to Pred(Self.Count) do     begin        item := Self[i];      if (item.p <> AItem.p) or (item.q <> AItem.q) then           Continue;         // use CompareStr if you want case sensitivity      if CompareText(item.s, AItem.s)=0 then           Exit(i);     end;  end; ---------------------------------------------------------------------- HappyLarry · 2016-07-29 14:01 @hnb Quoteoverride operator "=" (by class operator)How? Could you explain with some code? @Thaddy QuoteThe choice for naming the record Titem is unfortunate.I have tried other names but I get the same error. @All Does anyone know if TFPGList will work with records (I know it works with simple datatypes like integer and string)? ---------------------------------------------------------------------- Thaddy · 2016-07-29 15:25 Quote from: shobits1 on July 29, 2016, 03:55:38 pm but keep in mind there is no IndexOf function here No, but you have the much more powerful Locate and LookUp. No need for IndexOf, No need for record helpers. It is all there. ---------------------------------------------------------------------- Thaddy · 2016-07-29 15:32 Quote from: HappyLarry on July 29, 2016, 04:01:58 pm   Does anyone know if TFPGList will work with records (I know it works with simple datatypes like integer and string)? Unlike TFPGMap you will have to use Pointer to record and allocate them yourself, it seems, with  p:=New(TMyRecord) or something. During my experiments I ran into that. Should be solvable. ---------------------------------------------------------------------- shobits1 · 2016-07-29 15:56 Quote from: Thaddy on July 29, 2016, 05:25:44 pmQuote from: shobits1 on July 29, 2016, 03:55:38 pm but keep in mind there is no IndexOf function here (although you can add an the index as field) No, but you have the much more powerful Locate and LookUp. No need for IndexOf, No need for record helpers. It is all there. I know that, but maybe he needs the index for something else; and that's why I add he can use  an other field as index. ---------------------------------------------------------------------- HappyLarry · 2016-07-29 16:00 @shobits1 Nice code Back to the original question about TFPGObject - Shobit1's code means that IndexOf() behaves the way I would expect in TFPGObject. Now it is possible using TFPGObject to: 1. Sort by all three fields 2. Search for whole records 3. Search for just field 1 4. Search fields 2 and 3. Of course, the helper function relies on having a (string,integer,integer)-type record so it is not really built-in . . . Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;uses  sysutils, fgl; type    TItem = class      s:string;    p:integer;      q:integer;      procedure SetItem(f1:string;f2:integer;f3:integer);      procedure ShowItem;    end;     TObjectList = specialize TFPGObjectList;     TObjectListHelper = class helper for TObjectList      function IndexOf(AItem: TItem): Integer; overload;      function IndexOf(AItem: string) : Integer; overload;      function IndexOf(AItem: integer) : Integer; overload;    end;     procedure TItem.SetItem(f1:string;f2:integer;f3:integer);    begin       s:=f1;       p:=f2;       q:=f3;    end;     procedure TItem.ShowItem;    begin       writeln(s:12,   p:4,  q:4);    end;     function TObjectListHelper.IndexOf(AItem: TItem) : Integer; overload;    var    i: Integer;      item: TItem;    begin     result := -1;     for i := 0 to Pred(Self.Count) do     begin        item := Self[i];        if (item.p <> AItem.p) or (item.q <> AItem.q) then           Continue;         // use CompareStr if you want case sensitivity      if CompareText(item.s, AItem.s)=0 then           Exit(i);     end;  end;     function TObjectListHelper.IndexOf(AItem:string) : Integer; overload;    var      i: Integer;      item: TItem;    begin     result := -1;     for i := 0 to Pred(Self.Count) do     begin        item := Self[i];        if CompareText(item.s, AItem)=0 then        begin           Exit(i);        end;     end;    end;     function TObjectListHelper.IndexOf(AItem: integer) : Integer; overload;    var      i: Integer;      item: TItem;    begin     result := -1;     for i := 0 to Pred(Self.Count) do     begin        item := Self[i];        if (item.p = AItem) or (item.q = AItem) then        begin           Exit(i);        end;     end;    end;  var  A:TObjectList;  B:TItem; procedure ShowTitle(Message:string);begin     writeln;     writeln(Message);     writeln('--------------------------');end; procedure ShowObject(Z:TObjectList; k:integer);begin    If k <> -1 then   begin        writeln(k:4,  Z[k].s:12,   Z[k].p:4, Z[k].q:4);   end;end; procedure ShowObjectList(Z:TObjectList);var  k:integer;begin   For k:= 0 to Z.count-1 do   begin      writeln(k:4,  Z[k].s:12,   Z[k].p:4, Z[k].q:4);   end;   writeln;end; function compare1(const a, b: TItem): Integer;begin  If a.s > b.s then     Result := 1;  If a.s = b.s then     Result := 0;  If a.s < b.s then   Result := -1;end; function compare2(const a, b: TItem): Integer;begin  Result := a.p - b.p;end; function compare3(const a, b: TItem): Integer;begin  Result := a.q - b.q;end;  begin  ShowTitle('TFPGObjectList');   A:=TObjectList.create;  A.FreeObjects:=False;   ShowTitle('Adding objects');   B:=TItem.create;  B.SetItem('Lazarus',3,7);  A.Add(B);   B:=TItem.create;  B.SetItem('Python',8,5);  A.Add(B);   B:=TItem.create;  B.SetItem('Free Pascal',3,10);  A.Add(B);   B:=TItem.create;  B.SetItem('Visual Basic',5,11);  A.Add(B);  writeln('Index of B is ',A.IndexOf(B));   ShowTitle('Sort by column 1');  A.Sort(@Compare1);  ShowObjectList(A);  writeln(A.Count);   ShowTitle('Sort by column 2');  A.Sort(@Compare2);  ShowObjectList(A);  writeln(A.Count);   ShowTitle('Sort by column 3');  A.Sort(@Compare3);  ShowObjectList(A);  writeln(A.Count);   ShowTitle('Find the index given a complete item');  B:=TItem.create;  B.SetItem('Lazarus',3,7);  writeln('Index of Lazarus is : ',A.IndexOf(B));  ShowObject(A, A.IndexOf(B));   ShowTitle('Find the index given the key value string');  writeln('Index of Free Pascal is : ',A.IndexOf('Free Pascal'));  ShowObject(A, A.IndexOf('Free Pascal'));   ShowTitle('Find the index given a non-key value 10');  writeln('Index of 10 is : ',A.IndexOf(10));  ShowObject(A, A.IndexOf(10));   ShowTitle('Find the index given a non-key value 3');  writeln('Index of 3 is : ',A.IndexOf(3));  ShowObject(A, A.IndexOf(3));   B.free;  A.free;   writeln('---done----');  readln;end. ---------------------------------------------------------------------- Thaddy · 2016-07-29 16:20 @All, Molly We now have TDictionary! in trunk... I referred to Sparta generic library. As of today that is also in trunk and called rtl-generics. It is a bit more powerful than what we had in many ways. If you build trunk from this afternoon, you will see it appear, It is Delphi compatible. Here's an example along the lines of this discussion. This code needs trunk 34299 or higher because in that revision rtl- generics is added. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;{$mode delphi}uses  generics.collections; type  TItem = record    p:integer;    q:integer;    function SetItem(f2:integer;f3:integer):TItem;  end;   function TItem.SetItem(f2:integer;f3:integer):Titem;  begin    p:=f2;    q:=f3;    Result := self;  end;     procedure ShowObjectList(Z:TDictionary);  var    Item:Titem;    s:string;  begin    For s in Z.keys do      if Z.TryGetValue(S,Item) then        writeln('value''s for ',S,': ', Item.p :6, Item.q :6);  end; var  A:TDictionary;  B:TItem;begin  A:=TDictionary.Create;  try    A.Add('Lazarus',B.SetItem(28,7));     A.Add('Test',B.SetItem(7,28));  A.Add('Freepascal',B.SetItem(300,311));    ShowObjectList(A);    writeln('Count is:',A.Count);    writeln('If Test does exist change values else add Test');    A.AddOrSetValue('Test',B.SetItem(3000,3000));    writeln('If blaat does not exist add it, else change the values');    A.AddOrSetValue('Blaat',B.SetItem(0,0));    writeln('Count is:',A.Count);        ShowObjectList(A);    writeln('remove an element');    A.Remove('Test');    writeln('Count is:',A.Count);    ShowObjectList(A);  finally    A.free;  end;  readln;end.  btw: I tested delphi compatibilty with http://docwiki.embarcadero.com/CodeE xamples/Seattle/en/Generics_Collections_TDictionary_(Delphi)#Uses Note the uses clause for the code is missing but it is: uses sysutils,math, generics.collections.