Array helpers lazarus / 62-General ---------------------------------------------------------------------- Frogfather · 2022-03-25 07:43 Morning! I've been writing some helper methods for arrays. It's pretty simple and works well. However, looking at the code, the implementation for each type is almost identical: 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 TIntArrayHelper.indexOf(element: integer): integer;var  index:integer;begin  result:=-1;  for index:= 0 to pred(length(self)) do    if (self[index]=element) then      begin      result:=index;    exit;      end;end;             function TInt64ArrayHelper.indexOf(element: int64): integer;var  index:integer;begin  result:=-1;  for index:= 0 to pred(length(self)) do    if (self[index]=element) then      begin      result:=index;    exit;      end;end;   Looking at other posts here it looks like that's unavoidable - you can't write a Swift style array extension that works for all types. Before writing several near-identical methods I'd appreciate someone confirming that this is indeed the case. Thanks John C ---------------------------------------------------------------------- AlexTP · 2022-03-25 07:53 I only know that we have 'generic functions', found this https://forum.lazarus.freepascal.org/index.php?topic=33327.0 (FPC docs must exist). ---------------------------------------------------------------------- howardpc · 2022-03-25 08:38 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 objfpc}{$H+} uses  {$IFDEF UNIX} cthreads, {$ENDIF} Types, SysUtils; generic function GetIndex(aItem:T; aArr: array of T): SizeInt;begin  for Result := 0 to High(aArr) do    if aArr[Result] = aItem then      Exit;  Result := -1;end; var  sa: TStringArray = ('zero','one','two','three');  ia: TIntegerDynArray = (-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12); begin  WriteLn('5: ', specialize GetIndex(5, ia)=8);  WriteLn('13: ', specialize GetIndex(13, ia)=-1);  WriteLn('two: ', specialize GetIndex('two', sa));  WriteLn('test: ', specialize GetIndex('test', sa));  ReadLn;end. ---------------------------------------------------------------------- Frogfather · 2022-03-25 09:44 Thanks as always for quick replies! howardpc will give your suggestion a go - thanks. ---------------------------------------------------------------------- Zvoni · 2022-03-25 11:14 Suggestion (since you're writing a Helper for Integer-Arrays): I know that you cannot add a Field/Property to a Helper (only Functions), but i would introduce a Parameter "Sorted" to your IndexOf-Function. If True use a Binary-Search instead of sequentiell ---------------------------------------------------------------------- Frogfather · 2022-03-25 14:46 Thanks for suggestions. howardpc - your suggestion works very well for getIndex where an integer or int64 is being returned. If I wanted a function which returned the modified array (e.g. splice or addItem) how would I do that? The return type can't be 'array of T' or array. Or should I make it a procedure and pass by reference? 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 generic function AddItem(aItem:T; position: integer; aArr: array of T): ?What-goes-here?begin end; Thanks ---------------------------------------------------------------------- howardpc · 2022-03-25 17:07 One approach would be 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 program Project1; {$mode objfpc}{$H+} uses  {$IFDEF UNIX} cthreads, {$ENDIF}  Math, SysUtils, Types; type  generic Tarray = array of T; generic function InsertedI]"]>BlockedK(aItem: T; aIndex: SizeInt; var aArray: specialize Tarray; overwrite: Boolean=False): Boolean;var  i: SizeInt;begin  case overwrite of    True: case InRange(aIndex, 0, High(aArray)) of            False: Result := False;            True: begin                    aArray[aIndex] := aItem;                    Result := True;                  end;          end;    False: case InRange(aIndex, 0, Length(aArray)) of             False: Result := False;             True: begin                     SetLength(aArray, Succ(Length(aArray)));                     for i := Pred(High(aArray)) downto aIndex do                       aArray[Succ(i)] := aArray[i];                   aArray[aIndex] := aItem;                     Result := True;                   end;           end;  end;end; generic procedure WriteArray(aArray: specialize Tarray);var  i: SizeInt;begin  for i := 0 to High(aArray) do    Write(aArray[i], ' ');  WriteLn;end; var  ia: TIntegerDynArray = (13,14,15,17); begin  specialize WriteArray(ia);  WriteLn('InsertedI]"]>BlockedK(16, 3, ia, True) is ', specialize InsertedI]"]>BlockedK(16, 3, ia, True));   specialize WriteArray(ia);  WriteLn('InsertedI]"]>BlockedK(17, 4, ia, False) is ', specialize InsertedI]"]>BlockedK(17, 4, ia, False));  specialize WriteArray(ia);  WriteLn('InsertedI]"]>BlockedK(18, 6, ia, False) is ', specialize InsertedI]"]>BlockedK(18, 6, ia, False));  ReadLn;end. ---------------------------------------------------------------------- BobDog · 2022-03-25 17:58 Insert and delete are 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 {$mode delphi}{$rangeChecks on} procedure push(var a :T;index:int32;insert ion:T);begininsert(insertion,a,index);end; procedure pop(var a:T;index:array of int32;num:int32=1);vari:int32;beginfor i:=0 to high(index)  do delete(a,index[i],num);end;  type aos=array of string;type aoi=array of int32; vara1:aos;a2:aoi;i:integer;  begina1:= ['a','b','c','x','y','z'];for i:=0 to high(a1) do write(a1[i],' ');writeln('  original strings');push(a1,4,['9','10','11','12']);for i:=0 to high(a1) do write(a1[i],' ');writeln(' add 9 10 11 12 at position 4 ');push(a1,high(a1)+1,['Z']);for i:=0 to high(a1) do write(a1[i],' ');writeln(' add Z to top '); writeln;writeln('Delete odd numbers');a2:=[0,1,2,3,4,5,6,7,8,9];pop(a2,[1,2,3,4,5]);for i:=0 to high(a2) do write(a2[i],' ');writeln;writeln('Press return to end . . .');readln;end. ---------------------------------------------------------------------- Frogfather · 2022-03-25 19:42 Thanks for the suggestion howardpc - will give it a go. BobDog I didn't realise insert and delete were there - but I've only been using delphi/kylix/fpc for 20ish years (Oops!). ---------------------------------------------------------------------- Frogfather · 2022-03-25 20:57 Thanks all - my generic splice method now behaves (mostly) as the javascript version. Here's how it looks at the moment. I can then call that with my integer helper and int64 helper. 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 generic function splice(var aArray: specialize TArray; index, deleteCount: sizeInt; var newItems: specialize TArray  ): specialize TArray;var  normalizedCount, normalizedIndex, adjustIndex:sizeInt;begin result:= specialize TArray.create; //if index is greater than or equal to the size of the array then adjust it  if (index > high(aArray)) then normalizedIndex:= high(aArray)    else normalizedIndex:= index;  //TODO - if index is negative should start at end of array   //if the delete normalizedCount would take us off the end of the array then adjust it  if (deleteCount > high(aArray) - normalizedIndex) then    normalizedCount:= high(aArray) - normalizedIndex      else normalizedCount:= deleteCount;    if(deleteCount > 0) then     begin     //add the items that are to be deleted to the result array     for adjustIndex:=normalizedIndex to normalizedIndex + pred(normalizedCount) do       insert(aArray[adjustIndex],result,length(result));     for adjustIndex:= normalizedIndex to pred(length(aArray) - normalizedCount) do       aArray[adjustIndex]:= aArray[adjustIndex + normalizedCount];     setLength(aArray, length(aArray) - normalizedCount);     end;    if (newItems <> nil) then     begin     setLength(aArray, length(aArray) + length(newItems));      for adjustIndex:= high(aArray) downTo normalizedIndex + 1 do       aArray[adjustIndex]:= aArray[adjustIndex - length(newItems)];      for adjustIndex:= 0 to high(newItems) do       aArray[index+adjustIndex]:= newItems[adjustIndex];     end;end; ---------------------------------------------------------------------- PascalDragon · 2022-03-27 09:34 Quote from: howardpc on March 25, 2022, 06:07:26 pmOne approach would be 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 { snip }type  generic Tarray = array of T;{ snip } Please note that TArray<> is already declared in the System unit, no need to declare it manually as this might lead to confusion when both are used.