IndexMinBy, IndexMaxBy

MinBy, MaxBy - более эффективная реализация
GraphWPF - SaveToClipboard
This commit is contained in:
Mikhalkovich Stanislav 2024-09-25 11:53:02 +03:00
parent 3eb1d2bd85
commit 11981dbf47
10 changed files with 419 additions and 53 deletions

View file

@ -15,7 +15,7 @@ internal static class RevisionClass
public const string Major = "3";
public const string Minor = "10";
public const string Build = "0";
public const string Revision = "3546";
public const string Revision = "3547";
public const string MainVersion = Major + "." + Minor;
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;

View file

@ -1,4 +1,4 @@
%COREVERSION%=0
%REVISION%=3546
%MINOR%=10
%REVISION%=3547
%COREVERSION%=0
%MAJOR%=3

View file

@ -1 +1 @@
3.10.0.3546
3.10.0.3547

View file

@ -1 +1 @@
!define VERSION '3.10.0.3546'
!define VERSION '3.10.0.3547'

View file

@ -635,6 +635,12 @@ type
Redraw;
end;
static procedure KeyPress(c: char);
begin
if c.ToLower = 's' then
Window.SaveToClipboard;
end;
static procedure Resize;
begin
Redraw;
@ -647,8 +653,9 @@ initialization
Window.Title := 'Система координат';
finalization
Redraw;
OnMouseWheel := Handlers.MouseWheel;
OnMouseDown := Handlers.MouseDown;
OnMouseMove := Handlers.MouseMove;
OnResize := Handlers.Resize;
OnMouseWheel += Handlers.MouseWheel;
OnMouseDown += Handlers.MouseDown;
OnMouseMove += Handlers.MouseMove;
OnResize += Handlers.Resize;
OnKeyPress += Handlers.KeyPress;
end.

View file

@ -230,6 +230,8 @@ type
function Center: Point;
/// Сохраняет содержимое графического окна в файл с именем fname
procedure Save(fname: string);
/// Сохраняет содержимое графического окна в буфер обмена
procedure SaveToClipboard;
/// Восстанавливает содержимое графического окна из файла с именем fname
procedure Load(fname: string);
/// Заполняет содержимое графического окна обоями из файла с именем fname
@ -249,6 +251,8 @@ type
public
/// Сохраняет содержимое графического окна в файл с именем fname
procedure Save(fname: string);
/// Сохраняет содержимое графического окна в буфер обмена
procedure SaveToClipboard;
/// Восстанавливает содержимое графического окна из файла с именем fname
procedure Load(fname: string);
/// Очищает графическое окно белым цветом
@ -2005,7 +2009,7 @@ begin
end;
function GraphWindowType.GetHeight := InvokeReal(GraphWindowTypeGetHeightP);
procedure SaveWindowP(canvas: FrameworkElement; filename: string);
function SaveWindowToBitmapP(canvas: FrameworkElement): BitmapSource;
begin
HostToRenderBitmap;
var (scalex,scaley) := ScaleToDevice;
@ -2042,6 +2046,19 @@ begin
bmp.Render(canvas);
Result := bmp;
end;
procedure SaveWindowToClipboardP(canvas: FrameworkElement);
begin
var bmp := SaveWindowToBitmapP(canvas);
Clipboard.SetImage(bmp)
end;
procedure SaveWindowP(canvas: FrameworkElement; filename: string);
begin
var bmp := SaveWindowToBitmapP(canvas);
dpic[filename] := bmp;
(canvas as MyVisualHost).children.RemoveAt(0);
@ -2066,6 +2083,8 @@ end;
procedure GraphWindowType.Save(fname: string) := Invoke(SaveWindowP,host,fname);
procedure GraphWindowType.SaveToClipboard := Invoke(SaveWindowToClipboardP,host);
procedure GraphWindowType.Load(fname: string) := DrawImageUnscaled(0,0,fname);
procedure GraphWindowType.Fill(fname: string);
@ -2088,6 +2107,8 @@ function GraphWindowType.ClientRect: GRect := Rect(0,0,Width,Height);
procedure WindowTypeWPF.Save(fname: string) := GraphWindow.Save(fname);
procedure WindowTypeWPF.SaveToClipboard := GraphWindow.SaveToClipboard;
procedure WindowTypeWPF.Load(fname: string) := GraphWindow.Load(fname);
procedure WindowTypeClearP;

View file

@ -3013,6 +3013,8 @@ const
Format_InvalidString = 'Входная строка имела неверный формат!!Input string was not in a correct format';
Overflow_Int32 = 'Целочисленное переполнение!!Integer overflow';
FOR_STEP_CANNOT_BE_EQUAL0 = 'Шаг цикла for не может быт равен 0!!Step of the for loop cannot be equal to 0';
SEQUENCE_CANNOT_BE_EMPTY = 'Последовательность не может быть пустой!!Sequence cannot be empty';
ARRAY_CANNOT_BE_EMPTY = 'Массив не может быть пустым!!Array cannot be empty';
// -----------------------------------------------------
// WINAPI
// -----------------------------------------------------
@ -11007,43 +11009,103 @@ end;
// Дополнения 2024: Zip - синоним ZipTuple
/// Возвращает первый элемент последовательности с минимальным значением ключа
function MinBy<T, TKey>(Self: sequence of T; selector: T->TKey): T; extensionmethod;
function MinBy<T, TKey>(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod;
begin
if selector = nil then
raise new ArgumentNullException('selector');
var enumerator := Self.GetEnumerator();
if not enumerator.MoveNext() then
raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY));
var minElement := enumerator.Current;
var minKey := keySelector(minElement);
var comp := Comparer&<TKey>.Default;
Result := Self.Aggregate((min, x)-> comp.Compare(selector(x), selector(min)) < 0 ? x : min);
while enumerator.MoveNext() do
begin
var currentElement := enumerator.Current;
var currentKey := keySelector(currentElement);
if comp.Compare(currentKey,minKey) < 0 then
begin
minKey := currentKey;
minElement := currentElement;
end;
end;
Result := minElement;
end;
/// Возвращает первый элемент последовательности с максимальным значением ключа
function MaxBy<T, TKey>(Self: sequence of T; selector: T->TKey): T; extensionmethod;
function MaxBy<T, TKey>(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod;
begin
if selector = nil then
raise new ArgumentNullException('selector');
var enumerator := Self.GetEnumerator();
if not enumerator.MoveNext() then
raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY));
var maxElement := enumerator.Current;
var maxKey := keySelector(maxElement);
var comp := Comparer&<TKey>.Default;
Result := Self.Aggregate((max, x)-> comp.Compare(selector(x), selector(max)) > 0 ? x : max);
while enumerator.MoveNext() do
begin
var currentElement := enumerator.Current;
var currentKey := keySelector(currentElement);
if comp.Compare(currentKey,maxKey) > 0 then
begin
maxKey := currentKey;
maxElement := currentElement;
end;
end;
Result := maxElement;
end;
/// Возвращает последний элемент последовательности с минимальным значением ключа
function LastMinBy<T, TKey>(Self: sequence of T; selector: T->TKey): T; extensionmethod;
function LastMinBy<T, TKey>(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod;
begin
if selector = nil then
raise new ArgumentNullException('selector');
var enumerator := Self.GetEnumerator();
if not enumerator.MoveNext() then
raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY));
var minElement := enumerator.Current;
var minKey := keySelector(minElement);
var comp := Comparer&<TKey>.Default;
Result := Self.Aggregate((min, x)-> comp.Compare(selector(x), selector(min)) <= 0 ? x : min);
while enumerator.MoveNext() do
begin
var currentElement := enumerator.Current;
var currentKey := keySelector(currentElement);
if comp.Compare(currentKey,minKey) <= 0 then
begin
minKey := currentKey;
minElement := currentElement;
end;
end;
Result := minElement;
end;
/// Возвращает последний элемент последовательности с максимальным значением ключа
function LastMaxBy<T, TKey>(Self: sequence of T; selector: T->TKey): T; extensionmethod;
function LastMaxBy<T, TKey>(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod;
begin
if selector = nil then
raise new ArgumentNullException('selector');
var enumerator := Self.GetEnumerator();
if not enumerator.MoveNext() then
raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY));
var maxElement := enumerator.Current;
var maxKey := keySelector(maxElement);
var comp := Comparer&<TKey>.Default;
Result := Self.Aggregate((max, x)-> comp.Compare(selector(x), selector(max)) >= 0 ? x : max);
while enumerator.MoveNext() do
begin
var currentElement := enumerator.Current;
var currentKey := keySelector(currentElement);
if comp.Compare(currentKey,maxKey) > 0 then
begin
maxKey := currentKey;
maxElement := currentElement;
end;
end;
Result := maxElement;
end;
{function TakeLast<T>(Self: sequence of T; count: integer): sequence of T; extensionmethod;
@ -11672,7 +11734,100 @@ end;
function LastIndexMax<T>(Self: List<T>): integer; extensionmethod; where T: System.IComparable<T>;
begin
Result := Self.LastIndexMax(Self.Count - 1);
end;
end;
/// Возвращает индекс первого элемента с минимальным значением ключа
function IndexMinBy<T, TKey>(Self: array of T; keySelector: T -> TKey): integer; extensionmethod;
begin
if Self.Length = 0 then
raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY);
var minIndex := 0;
var minKey := keySelector(Self[0]);
var comp := Comparer&<TKey>.Default;
for var i := 1 to Self.Length - 1 do
begin
var currentKey := keySelector(Self[i]);
if comp.Compare(currentKey,minKey) < 0 then
begin
minKey := currentKey;
minIndex := i;
end;
end;
Result := minIndex;
end;
/// Возвращает индекс первого элемента с максимальным значением ключа
function IndexMaxBy<T, TKey>(Self: array of T; keySelector: T -> TKey): integer; extensionmethod;
begin
if Self.Length = 0 then
raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY);
var maxIndex := 0;
var maxKey := keySelector(Self[0]);
var comp := Comparer&<TKey>.Default;
for var i := 1 to Self.Length - 1 do
begin
var currentKey := keySelector(Self[i]);
if comp.Compare(currentKey,maxKey) > 0 then
begin
maxKey := currentKey;
maxIndex := i;
end;
end;
Result := maxIndex;
end;
/// Возвращает индекс последнего элемента с минимальным значением ключа
function LastIndexMinBy<T, TKey>(Self: array of T; keySelector: T -> TKey): integer; extensionmethod;
begin
if Self.Length = 0 then
raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY);
var minIndex := 0;
var minKey := keySelector(Self[0]);
var comp := Comparer&<TKey>.Default;
for var i := 1 to Self.Length - 1 do
begin
var currentKey := keySelector(Self[i]);
if comp.Compare(currentKey,minKey) <= 0 then
begin
minKey := currentKey;
minIndex := i;
end;
end;
Result := minIndex;
end;
/// Возвращает индекс последнего элемента с максимальным значением ключа
function LastIndexMaxBy<T, TKey>(Self: array of T; keySelector: T -> TKey): integer; extensionmethod;
begin
if Self.Length = 0 then
raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY);
var maxIndex := 0;
var maxKey := keySelector(Self[0]);
var comp := Comparer&<TKey>.Default;
for var i := 1 to Self.Length - 1 do
begin
var currentKey := keySelector(Self[i]);
if comp.Compare(currentKey,maxKey) >= 0 then
begin
maxKey := currentKey;
maxIndex := i;
end;
end;
Result := maxIndex;
end;
/// Заменяет в массиве все вхождения одного значения на другое
/// Заменяет в списке все вхождения одного значения на другое
@ -12716,7 +12871,7 @@ begin
Result := Self[i];
end;
/// Возвращает индекс первого минимального элемента начиная с позиции index
/// Возвращает индекс первого минимального элемента
function IndexMin<T>(Self: array of T; index: integer := 0): integer; extensionmethod; where T: IComparable<T>;
begin
var min := Self[index];
@ -12729,7 +12884,7 @@ begin
end;
end;
/// Возвращает индекс первого максимального элемента начиная с позиции index
/// Возвращает индекс первого максимального элемента
function IndexMax<T>(Self: array of T; index: integer := 0): integer; extensionmethod; where T: System.IComparable<T>;
begin
var max := Self[index];

View file

@ -635,6 +635,12 @@ type
Redraw;
end;
static procedure KeyPress(c: char);
begin
if c.ToLower = 's' then
Window.SaveToClipboard;
end;
static procedure Resize;
begin
Redraw;
@ -647,8 +653,9 @@ initialization
Window.Title := 'Система координат';
finalization
Redraw;
OnMouseWheel := Handlers.MouseWheel;
OnMouseDown := Handlers.MouseDown;
OnMouseMove := Handlers.MouseMove;
OnResize := Handlers.Resize;
OnMouseWheel += Handlers.MouseWheel;
OnMouseDown += Handlers.MouseDown;
OnMouseMove += Handlers.MouseMove;
OnResize += Handlers.Resize;
OnKeyPress += Handlers.KeyPress;
end.

View file

@ -230,6 +230,8 @@ type
function Center: Point;
/// Сохраняет содержимое графического окна в файл с именем fname
procedure Save(fname: string);
/// Сохраняет содержимое графического окна в буфер обмена
procedure SaveToClipboard;
/// Восстанавливает содержимое графического окна из файла с именем fname
procedure Load(fname: string);
/// Заполняет содержимое графического окна обоями из файла с именем fname
@ -249,6 +251,8 @@ type
public
/// Сохраняет содержимое графического окна в файл с именем fname
procedure Save(fname: string);
/// Сохраняет содержимое графического окна в буфер обмена
procedure SaveToClipboard;
/// Восстанавливает содержимое графического окна из файла с именем fname
procedure Load(fname: string);
/// Очищает графическое окно белым цветом
@ -2005,7 +2009,7 @@ begin
end;
function GraphWindowType.GetHeight := InvokeReal(GraphWindowTypeGetHeightP);
procedure SaveWindowP(canvas: FrameworkElement; filename: string);
function SaveWindowToBitmapP(canvas: FrameworkElement): BitmapSource;
begin
HostToRenderBitmap;
var (scalex,scaley) := ScaleToDevice;
@ -2042,6 +2046,19 @@ begin
bmp.Render(canvas);
Result := bmp;
end;
procedure SaveWindowToClipboardP(canvas: FrameworkElement);
begin
var bmp := SaveWindowToBitmapP(canvas);
Clipboard.SetImage(bmp)
end;
procedure SaveWindowP(canvas: FrameworkElement; filename: string);
begin
var bmp := SaveWindowToBitmapP(canvas);
dpic[filename] := bmp;
(canvas as MyVisualHost).children.RemoveAt(0);
@ -2066,6 +2083,8 @@ end;
procedure GraphWindowType.Save(fname: string) := Invoke(SaveWindowP,host,fname);
procedure GraphWindowType.SaveToClipboard := Invoke(SaveWindowToClipboardP,host);
procedure GraphWindowType.Load(fname: string) := DrawImageUnscaled(0,0,fname);
procedure GraphWindowType.Fill(fname: string);
@ -2088,6 +2107,8 @@ function GraphWindowType.ClientRect: GRect := Rect(0,0,Width,Height);
procedure WindowTypeWPF.Save(fname: string) := GraphWindow.Save(fname);
procedure WindowTypeWPF.SaveToClipboard := GraphWindow.SaveToClipboard;
procedure WindowTypeWPF.Load(fname: string) := GraphWindow.Load(fname);
procedure WindowTypeClearP;

View file

@ -3013,6 +3013,8 @@ const
Format_InvalidString = 'Входная строка имела неверный формат!!Input string was not in a correct format';
Overflow_Int32 = 'Целочисленное переполнение!!Integer overflow';
FOR_STEP_CANNOT_BE_EQUAL0 = 'Шаг цикла for не может быт равен 0!!Step of the for loop cannot be equal to 0';
SEQUENCE_CANNOT_BE_EMPTY = 'Последовательность не может быть пустой!!Sequence cannot be empty';
ARRAY_CANNOT_BE_EMPTY = 'Массив не может быть пустым!!Array cannot be empty';
// -----------------------------------------------------
// WINAPI
// -----------------------------------------------------
@ -11007,43 +11009,103 @@ end;
// Дополнения 2024: Zip - синоним ZipTuple
/// Возвращает первый элемент последовательности с минимальным значением ключа
function MinBy<T, TKey>(Self: sequence of T; selector: T->TKey): T; extensionmethod;
function MinBy<T, TKey>(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod;
begin
if selector = nil then
raise new ArgumentNullException('selector');
var enumerator := Self.GetEnumerator();
if not enumerator.MoveNext() then
raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY));
var minElement := enumerator.Current;
var minKey := keySelector(minElement);
var comp := Comparer&<TKey>.Default;
Result := Self.Aggregate((min, x)-> comp.Compare(selector(x), selector(min)) < 0 ? x : min);
while enumerator.MoveNext() do
begin
var currentElement := enumerator.Current;
var currentKey := keySelector(currentElement);
if comp.Compare(currentKey,minKey) < 0 then
begin
minKey := currentKey;
minElement := currentElement;
end;
end;
Result := minElement;
end;
/// Возвращает первый элемент последовательности с максимальным значением ключа
function MaxBy<T, TKey>(Self: sequence of T; selector: T->TKey): T; extensionmethod;
function MaxBy<T, TKey>(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod;
begin
if selector = nil then
raise new ArgumentNullException('selector');
var enumerator := Self.GetEnumerator();
if not enumerator.MoveNext() then
raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY));
var maxElement := enumerator.Current;
var maxKey := keySelector(maxElement);
var comp := Comparer&<TKey>.Default;
Result := Self.Aggregate((max, x)-> comp.Compare(selector(x), selector(max)) > 0 ? x : max);
while enumerator.MoveNext() do
begin
var currentElement := enumerator.Current;
var currentKey := keySelector(currentElement);
if comp.Compare(currentKey,maxKey) > 0 then
begin
maxKey := currentKey;
maxElement := currentElement;
end;
end;
Result := maxElement;
end;
/// Возвращает последний элемент последовательности с минимальным значением ключа
function LastMinBy<T, TKey>(Self: sequence of T; selector: T->TKey): T; extensionmethod;
function LastMinBy<T, TKey>(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod;
begin
if selector = nil then
raise new ArgumentNullException('selector');
var enumerator := Self.GetEnumerator();
if not enumerator.MoveNext() then
raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY));
var minElement := enumerator.Current;
var minKey := keySelector(minElement);
var comp := Comparer&<TKey>.Default;
Result := Self.Aggregate((min, x)-> comp.Compare(selector(x), selector(min)) <= 0 ? x : min);
while enumerator.MoveNext() do
begin
var currentElement := enumerator.Current;
var currentKey := keySelector(currentElement);
if comp.Compare(currentKey,minKey) <= 0 then
begin
minKey := currentKey;
minElement := currentElement;
end;
end;
Result := minElement;
end;
/// Возвращает последний элемент последовательности с максимальным значением ключа
function LastMaxBy<T, TKey>(Self: sequence of T; selector: T->TKey): T; extensionmethod;
function LastMaxBy<T, TKey>(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod;
begin
if selector = nil then
raise new ArgumentNullException('selector');
var enumerator := Self.GetEnumerator();
if not enumerator.MoveNext() then
raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY));
var maxElement := enumerator.Current;
var maxKey := keySelector(maxElement);
var comp := Comparer&<TKey>.Default;
Result := Self.Aggregate((max, x)-> comp.Compare(selector(x), selector(max)) >= 0 ? x : max);
while enumerator.MoveNext() do
begin
var currentElement := enumerator.Current;
var currentKey := keySelector(currentElement);
if comp.Compare(currentKey,maxKey) > 0 then
begin
maxKey := currentKey;
maxElement := currentElement;
end;
end;
Result := maxElement;
end;
{function TakeLast<T>(Self: sequence of T; count: integer): sequence of T; extensionmethod;
@ -11672,7 +11734,100 @@ end;
function LastIndexMax<T>(Self: List<T>): integer; extensionmethod; where T: System.IComparable<T>;
begin
Result := Self.LastIndexMax(Self.Count - 1);
end;
end;
/// Возвращает индекс первого элемента с минимальным значением ключа
function IndexMinBy<T, TKey>(Self: array of T; keySelector: T -> TKey): integer; extensionmethod;
begin
if Self.Length = 0 then
raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY);
var minIndex := 0;
var minKey := keySelector(Self[0]);
var comp := Comparer&<TKey>.Default;
for var i := 1 to Self.Length - 1 do
begin
var currentKey := keySelector(Self[i]);
if comp.Compare(currentKey,minKey) < 0 then
begin
minKey := currentKey;
minIndex := i;
end;
end;
Result := minIndex;
end;
/// Возвращает индекс первого элемента с максимальным значением ключа
function IndexMaxBy<T, TKey>(Self: array of T; keySelector: T -> TKey): integer; extensionmethod;
begin
if Self.Length = 0 then
raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY);
var maxIndex := 0;
var maxKey := keySelector(Self[0]);
var comp := Comparer&<TKey>.Default;
for var i := 1 to Self.Length - 1 do
begin
var currentKey := keySelector(Self[i]);
if comp.Compare(currentKey,maxKey) > 0 then
begin
maxKey := currentKey;
maxIndex := i;
end;
end;
Result := maxIndex;
end;
/// Возвращает индекс последнего элемента с минимальным значением ключа
function LastIndexMinBy<T, TKey>(Self: array of T; keySelector: T -> TKey): integer; extensionmethod;
begin
if Self.Length = 0 then
raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY);
var minIndex := 0;
var minKey := keySelector(Self[0]);
var comp := Comparer&<TKey>.Default;
for var i := 1 to Self.Length - 1 do
begin
var currentKey := keySelector(Self[i]);
if comp.Compare(currentKey,minKey) <= 0 then
begin
minKey := currentKey;
minIndex := i;
end;
end;
Result := minIndex;
end;
/// Возвращает индекс последнего элемента с максимальным значением ключа
function LastIndexMaxBy<T, TKey>(Self: array of T; keySelector: T -> TKey): integer; extensionmethod;
begin
if Self.Length = 0 then
raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY);
var maxIndex := 0;
var maxKey := keySelector(Self[0]);
var comp := Comparer&<TKey>.Default;
for var i := 1 to Self.Length - 1 do
begin
var currentKey := keySelector(Self[i]);
if comp.Compare(currentKey,maxKey) >= 0 then
begin
maxKey := currentKey;
maxIndex := i;
end;
end;
Result := maxIndex;
end;
/// Заменяет в массиве все вхождения одного значения на другое
/// Заменяет в списке все вхождения одного значения на другое
@ -12716,7 +12871,7 @@ begin
Result := Self[i];
end;
/// Возвращает индекс первого минимального элемента начиная с позиции index
/// Возвращает индекс первого минимального элемента
function IndexMin<T>(Self: array of T; index: integer := 0): integer; extensionmethod; where T: IComparable<T>;
begin
var min := Self[index];
@ -12729,7 +12884,7 @@ begin
end;
end;
/// Возвращает индекс первого максимального элемента начиная с позиции index
/// Возвращает индекс первого максимального элемента
function IndexMax<T>(Self: array of T; index: integer := 0): integer; extensionmethod; where T: System.IComparable<T>;
begin
var max := Self[index];