I have defined a dynamic array type as follows:
TMyIntegerArray = array of integer:
I would like to use an IndexOf
function as I would do if it were a TObject
's descendant:
var
MyArray : TMyIntegerArray;
i : integer:
begin
//...
i := MyArray.IndexOf(10);
//...
end;
At the moment, the only solution I've found is to write a function who accepts the array and the target value as parameters:
function IndexOf(AArray : TMyIntegerArray; ATargetValue : integer; AOffset : integer = 0);
begin
Result := AOffset;
while(Result < Length(AArray)) do
begin
if(AArray[Result] = ATargetValue)
then Exit;
Result := Result + 1;
end;
Result := -1;
end;
Can TMyIntegerArray
type have a function like IndexOf
?
Further Informations:
Currently, I'm using Delphi2007 but I'm also interested in knowing if there's any way to add methods to array types in newer Delphi's versions.
In newer versions of Delphi (XE3+), it is possible to implement methods to array types with record helpers
:
program ProjectTest;
{$APPTYPE CONSOLE}
Type
TMyArray = array of integer;
TMyArrayHelper = record helper for TMyArray
procedure Print;
function IndexOf(ATargetValue : integer; AOffset : integer = 0): Integer;
end;
procedure TMyArrayHelper.Print;
var
i: Integer;
begin
for i in Self do WriteLn(i); // Use Self for variable reference
end;
function TMyArrayHelper.IndexOf(ATargetValue : integer; AOffset : integer = 0): Integer;
begin
Result := AOffset;
while(Result < Length(Self)) do
begin
if(Self[Result] = ATargetValue)
then Exit;
Result := Result + 1;
end;
Result := -1;
end;
var
myArr : TMyArray;
begin
myArr := [0,1,2]; // A neat way to populate a dynamic array (XE7+)
myArr.Print;
WriteLn(myArr.IndexOf(2));
ReadLn;
end.
Note: You can skip the TMyArray
type declaration and use TArray<Integer>
for a more relaxed type resolution. As always with record helpers, there can be only one helper attached to a type (and the one that will be used is the one nearest in scope).
This type of helper is called an intrinsic type helper, where the compiler puts an implicit record structure around the type.
Although LU RD showed a direct solution to your question, I am going to add a slightly different approach based on generics. This has the advantage of providing a valid solution for different array types in one place.
For Delphi versions which supports generics, one can adopt the way used in TArray found in System.Generics.Collections. This is a straight forward extension of that class introducing a function IndexOf:
type
TArrayExt = class(TArray)
public
class function IndexOf<T>(const Values: array of T; const Item: T; const Comparer: IEqualityComparer<T>; Index, Count:
Integer): Integer; overload; static;
class function IndexOf<T>(const Values: array of T; const Item: T; const Comparer: IEqualityComparer<T>): Integer; overload;
static;
class function IndexOf<T>(const Values: array of T; const Item: T): Integer; overload; static;
end;
class function TArrayExt.IndexOf<T>(const Values: array of T; const Item: T; const Comparer: IEqualityComparer<T>; Index,
Count: Integer): Integer;
var
I: Integer;
begin
if (Index < Low(Values)) or ((Index > High(Values)) and (Count > 0))
or (Index + Count - 1 > High(Values)) or (Count < 0)
or (Index + Count < 0) then
raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
if Count = 0 then
begin
Exit(-1);
end;
for I := Index to Index + Count - 1 do begin
if Comparer.Equals(Item, Values[I]) then begin
Exit(I);
end;
end;
Result := -1;
end;
class function TArrayExt.IndexOf<T>(const Values: array of T; const Item: T; const Comparer: IEqualityComparer<T>): Integer;
begin
Result := IndexOf<T>(Values, Item, Comparer, Low(Values), Length(Values));
end;
class function TArrayExt.IndexOf<T>(const Values: array of T; const Item: T): Integer;
begin
result := IndexOf<T>(Values, Item, TEqualityComparer<T>.Default, Low(Values), Length(Values));
end;
A simple use case could look like this:
procedure Main;
var
arr: TArray<Integer>;
N: Integer;
begin
arr := TArray<Integer>.Create(5, 7, 3, 4, 2);
repeat
Readln(N);
N := TArrayExt.IndexOf(arr, N);
Writeln(N);
until false;
end;
For Delphi 2009 and above you can use a generic list:
uses System.Generics.Collections;
var
MyArray : TList<integer>;
i : integer;
begin
MyArray := TList<integer>.Create;
MyArray.Add(3);
MyArray.Add(7);
MyArray.Add(10);
i := MyArray.IndexOf(10);
end;
In Delphi 2007 you might use a custom record:
type
TMyArray = record
private
TheArray : array of integer;
public
procedure Add(Value : integer);
function IndexOf(Value : integer) : integer;
function Length : integer;
end;
procedure TMyArray.Add(Value : integer);
var
i : integer;
begin
i := length(TheArray);
setlength(TheArray,i+1);
TheArray[i] := Value;
end;
function TMyArray.IndexOf(Value : integer) : integer;
var
i : integer;
begin
for i := 0 to length(TheArray)-1 do
begin
if TheArray[i] = Value then
begin
Result := i;
exit;
end;
end;
Result := -1;
end;
function TMyArray.Length : integer;
begin
Result := length(TheArray);
end;
procedure MyFunction;
var
MyArray : TMyArray;
i : integer;
begin
MyArray.Add(3);
MyArray.Add(7);
MyArray.Add(10);
i := MyArray.IndexOf(10);
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With