Help/ideas for my objectlist lazarus / 21-General ---------------------------------------------------------------------- stokie-ant · 2023-09-08 02:06 I'll try best explain my problem I have a bunch of objects in a tfpobjectlist. Each object has a unique id. The id is not available at object creation but is added later so I can't use an objectdictionary. I decided to add a dictionary list that keeps the id as the key and the index of the object as the value. When the id is given to the object the entry is made in the dictionary. I have been able to get rid of many for loops doing it like this but now I've realised I have objects a(0), b(1), c(2), d(3) and remove b, the entry for b (1) will be removed from the dictionary too. Now when I get the index for c from the dictionary(2), that index is now for d because everything has moved down one. c is now 1. I need a way to automatically update the key, values of the dictionary. I could do it with a loop when an object is removed but I wanted to get rid of loops and I could be adding and removing thousands of objects at a time. Does an object or list have any form of notification when an index is changed? ---------------------------------------------------------------------- Jorg3000 · 2023-09-08 02:48 Hi! I wouldn't store the index at all and use .IndexOf(object) instead. I think changing a stored index value for all list items on a single change will need more runtime than simply looking for .IndexOf(object) ---------------------------------------------------------------------- cdbc · 2023-09-08 11:13 Hi You could use the "Decorator" pattern, i.e.: Create an objectlist, that holds a TFPObjectlist inside and surface the properties and methods from TFPObjectlist, you need and add your own event mechanism or implement the observer pattern, e.g.: IFPOObserved interface in your objectlist... For decorator, see contnrs unit and for observer, see TPersistent implementation in Classes unit. Just my Nickel's worth  Regards Benny ---------------------------------------------------------------------- paweld · 2023-09-08 11:16 maybe something like this - based on TFPGMapObject: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 unit MolUnit; {$mode ObjFPC}{$H+} interface uses  Classes, SysUtils, fgl; type   { TMyObjectList }   TMyObjectList = class(specialize TFPGMapObject)  type    TIdList = specialize TFPGMap;  private    FIdList: TIdList;  public    constructor Create;    destructor Destroy; override;    function Add(aData: TObject): Integer;    procedure Delete(aIndex: Integer);  procedure DeleteById(aId: String);    function IndexOfId(aId: String): Integer;    function IndexOfObject(aData: TObject): Integer;    procedure RegisterId(aIndex: Integer; aId: String);    procedure ChangeId(aId, aNewId: String);    function GetId(aIndex: Integer): String;  end; implementation { TMyObjectList } constructor TMyObjectList.Create;begin  inherited Create;  Duplicates := dupIgnore;  Sorted := True;  FIdList := TIdList.Create;  FIdList.Duplicates := dupIgnore;  FIdList.Sorted := True;end; destructor TMyObjectList.Destroy;begin  FIdList.Free;  inherited Destroy;end; function TMyObjectList.Add(aData: TObject): Integer;var  objidx: Integer;begin  if Count > 0 then    objidx := Keys[Count - 1] + 1  else    objidx := 0;  Result := inherited Add(objidx, aData);end; procedure TMyObjectList.Delete(aIndex: Integer);var  i, objidx: Integer;begin  objidx := Keys[aIndex];  inherited Delete(aIndex);  for i := 0 to FIdList.Count - 1 do  begin  if FIdList.Data[i] = objidx then    begin      FIdList.Delete(i);    break;    end;  end;end; procedure TMyObjectList.DeleteById(aId: String);var  idx, objidx: Integer;begin  idx := FIdList.IndexOf(aId);  if idx >= 0 then  begin    objidx := FIdList.Data[idx];    idx := IndexOf(objidx);    if idx >= 0 then      Delete(idx);  end;end; function TMyObjectList.IndexOfId(aId: String): Integer;var  idx: Integer;begin  Result := -1;  idx := FIdList.IndexOf(aId);  if idx >= 0 then    Result := IndexOf(FIdList.Data[idx]);end; function TMyObjectList.IndexOfObject(aData: TObject): Integer;var  i: Integer;begin  Result := -1;  for i := 0 to Count - 1 do  begin    if Data[i] = aData then    begin      Result := i;      break;    end;  end;end; procedure TMyObjectList.RegisterId(aIndex: Integer; aId: String);var  idx, objidx: Integer;begin  if aIndex < 0 then    exit;  objidx := Keys[aIndex];  idx := FIdList.IndexOf(aId);  if idx >= 0 then  begin    if FIdList.Data[idx] <> objidx then      raise Exception.Create('This Id is exists!');  end  else    FIdList.Add(aId, objidx);end; procedure TMyObjectList.ChangeId(aId, aNewId: String);var  idx, objidx: Integer;begin  idx := FIdList.IndexOf(aId);  if idx >= 0 then  begin    objidx := FIdList.Data[idx];    if FIdList.Data[idx] <> objidx then      raise Exception.Create('This Id is exists!');  end  else    FIdList.Add(aId, objidx);end; function TMyObjectList.GetId(aIndex: Integer): String;var  i, idx, objidx: Integer;begin  Result := '';  objidx := Keys[aIndex];  idx := -1;  for i := 0 to FIdList.Count - 1 do  begin    if FIdList.Data[i] = objidx then    begin      idx := i;      break;    end;  end;  if idx >= 0 then    Result := FIdList.Keys[idx];end; end. example of use in the attachment ---------------------------------------------------------------------- alpine · 2023-09-08 11:17 Quote from: stokie-ant on September 08, 2023, 04:06:48 amDoes an object or list have any form of notification when an index is changed? TList and descendants implements IFPObserved. TObjectList is a TList descendant but TFPObjectList isn't. ---------------------------------------------------------------------- stokie-ant · 2023-09-08 11:27 Quote from: Jorg3000 on September 08, 2023, 04:48:36 amHi! I wouldn't store the index at all and use .IndexOf(object) instead. I think changing a stored index value for all list items on a single change will need more runtime than simply looking for .IndexOf(object) Thanks for that. I don't already have an instance of object to pass to IndexOf but after reading your reply it's so obvious. DictionaryList is now . When the ID is added to the object in objectlist the object is added with its ID to the dictionarylist so that can give me the object that I can then pass to IndexOf and that seems to be perfect ---------------------------------------------------------------------- stokie-ant · 2023-09-08 11:33 Thanks for the replies. Its given me some ideas for further improvements ---------------------------------------------------------------------- alpine · 2023-09-08 11:51 IndexOf(Object) is a loop by itself. You don't want to write loops or to use loops? You can keep the objects with an ID only into the dictionary. Why bother with housekeeping the list? ---------------------------------------------------------------------- stokie-ant · 2023-09-08 15:18 Quote from: alpine on September 08, 2023, 01:51:04 pmIndexOf(Object) is a loop by itself. You don't want to write loops or to use loops? A bit of both but mainly it's about reducing processing time when finding and removing the objects. Originally these objects were in a simple array and there was only a few (~ 40) and all static so it was a case of 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 for i := 0 to length(objects) - 1 do  if objects[i].id = idToFind then    Description := objects[i].description and to render 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 for i := 0 to length(objects) - 1 do  objects[i].render But now I'm adding and removing objects dynamically and sometimes its thousands of these. It's an OpenGL program and the ID is from glGenLists. The ID is not available until after the object has been initially rendered. The initial render is only done when the object comes into view. Quote from: alpine on September 08, 2023, 01:51:04 pmYou can keep the objects with an ID only into the dictionary. Why bother with housekeeping the list? I could but then where would the waiting unprocessed objects with no id go? It would have to be another list. Sometimes the objects might need to be removed before they have been rendered