-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add generic Max, Min, Mid routines to csdb collection. #8
Comments
Here's an example function function Max<T>(const A: array of T; Compare: TComparison<T>): T; overload;
begin
Assert(Length(A) > 0);
Result := A[Low(A)];
for var I := Succ(Low(A)) to High(A) do
begin
if Compare(A[I], Result) > 0 then
Result := A[I];
end;
end; |
From what I've read generic global functions can't be declared, so it looks as though the generic functions may need to be grouped together in a static class or record, e.g.: type
TMinMax = record
class function Max<T>(const A: array of T; Compare: TComparison<T>): T; overload; static;
class function Min<T>(const A: array of T; Compare: TComparison<T>): T; overload; static;
class function Max<T>(const A, B: T; Compare: TComparison<T>): T; overload; static;
class function Min<T>(const A, B: T; Compare: TComparison<T>): T; overload; static;
end; The reason for putting the type parameter on the metho, rather than the records is so that non-generic methods can be included. For example: type
TMinMax = record
class function Max<T>(const A: array of T; Compare: TComparison<T>): T; overload; static;
// ...
class function Max(const A: array of Integer): Integer; overload; static;
end; |
Can't declare a function or procedure with generic type - instead need to declare a static class or record with generic methods. Tested a record with generic methods in CodeSnip and it compiled in Delphi 11. |
Could generalise this for type
TElemSelector = record
public
type
TSelectFn<T> = reference to function(const ACurrent, ACandidate: T; AComparer: IComparer<T>): T;
class function Select<T>(const A: array of T; ASelector: TSelectFn<T>; AComparer: IComparer<T> = nil): T; static;
class function Max<T>(const A: array of T; AComparer: IComparer<T> = nil): T; static;
// ... etc
end;
class function TElemSelector.Select<T>(const A: array of T; ASelector: TSelectFn<T>; AComparer: IComparer<T> = nil): T;
begin
Assert(Length(A) > 0);
if not Assigned(AComparer) then
AComparer := TComparer<T>.Default;
Result := A[Low(A)];
for var I := Succ(Low(A)) to High(A) do
begin
Result := ASelector(Result, A[I], AComparer);
end;
end;
class function TElemSelector.Max<T>(const A: array of T; AComparer: IComparer<T>): T;
begin
Result := Select(
A,
function(const ACurrent, ACandidate: T; AComparer: IComparer<T>): T
begin
if AComparer.Compare(ACurrent, ACandidate) > 0 the
Result := ACurrent
else
Result := ACandidate;
end,
AComparer
);
end |
Thinking about this further the |
This comment is now addressed by issue #43
It would be better to create a differently named record with methods that is more generalised that has array operations based on those of JavaScript. E.g.s forEach(), some(), all() & map(). |
It's difficult to see how to generalise The easiest way of finding the mid value in an array is to sort the array and pick the middle element if the array length is odd or to average the middle two elements if even. This is the same as taking the median value if the array. This is dealt with in issue #16. ❗ For the above reasons we won't be adding a |
There's already a |
Not only is the above method pretty useless, as noted above, it's also badly named. Surely a selector method should return an array of every elem that passes some test? All it needs as a paramter is the element being considered, it can simply be a Here's some code that should perform a selection ( class function TArrayUtils.Select<T>(const A: array of T; const ASelector: TPredicate<T>): TArray<T>;
begin
Assert(Length(A) > 0);
Assert(Assigned(ASelector));
SetLength(Result, Length(A));
var ResIdx: Integer := 0;
for var Elem in A do
begin
if ASelector(Elem) then
begin
Result[ResIdx] := Elem;
Inc(ResIdx);
end;
end;
SetLength(Result, ResIdx);
end; |
All the above waffle about a So |
class function TArrayUtils.Max<T>(const A: array of T; AComparer: IComparer<T>): T;
begin
Assert(System.Length(A) > 0);
Result := A[0];
for var Idx := 1 to Pred(System.Length(A)) do
if AComparer.Compare(A[Idx], Result) > 0 then
Result := A[Idx];
end;
class function TArrayUtils.Min<T>(const A: array of T; AComparer: IComparer<T>): T;
begin
Assert(System.Length(A) > 0);
Result := A[0];
for var Idx := 1 to Pred(System.Length(A)) do
if AComparer.Compare(A[Idx], Result) < 0 then
Result := A[Idx];
end; There could be an overload where a comparer closure is passed as a parameter instead of |
There are lots of overloaded Max, Min and Mid routines in the Maths category of the csdb collection, but it's crying out for some generic versions.
The text was updated successfully, but these errors were encountered: