From 8503c77b410dbb081897fd4a6615bd43240b721a Mon Sep 17 00:00:00 2001 From: Daniele Teti Date: Sun, 3 Nov 2024 17:21:58 +0100 Subject: [PATCH] Added HigherOrder.Map with some overloads --- samples/higher_order_functions/MainFormU.dfm | 26 ++++-- samples/higher_order_functions/MainFormU.pas | 58 +++++++++++++ sources/MVCFramework.Utils.pas | 88 +++++++++++++++++++- 3 files changed, 162 insertions(+), 10 deletions(-) diff --git a/samples/higher_order_functions/MainFormU.dfm b/samples/higher_order_functions/MainFormU.dfm index 5adfe264..7e48d611 100644 --- a/samples/higher_order_functions/MainFormU.dfm +++ b/samples/higher_order_functions/MainFormU.dfm @@ -47,7 +47,7 @@ object MainForm: TMainForm object btnMapAddStars: TButton Left = 8 Top = 27 - Width = 95 + Width = 74 Height = 30 Caption = 'Add Stars' TabOrder = 0 @@ -61,7 +61,6 @@ object MainForm: TMainForm Anchors = [akLeft, akTop, akBottom] ItemHeight = 13 TabOrder = 1 - ExplicitHeight = 219 end object btnFilterBetween: TButton Left = 380 @@ -81,7 +80,6 @@ object MainForm: TMainForm Anchors = [akLeft, akTop, akBottom] ItemHeight = 13 TabOrder = 3 - ExplicitHeight = 219 end object btnReduceSum: TButton Left = 194 @@ -100,7 +98,6 @@ object MainForm: TMainForm Anchors = [akLeft, akTop, akBottom] ItemHeight = 13 TabOrder = 5 - ExplicitHeight = 219 end object btnReduceMin: TButton Left = 194 @@ -152,7 +149,7 @@ object MainForm: TMainForm object btnMapCapitalize: TButton Left = 8 Top = 63 - Width = 95 + Width = 74 Height = 30 Caption = 'Capitalize' TabOrder = 11 @@ -175,7 +172,6 @@ object MainForm: TMainForm Anchors = [akLeft, akTop, akBottom] ItemHeight = 13 TabOrder = 13 - ExplicitHeight = 219 end object btnForEachWithException: TButton Left = 566 @@ -186,4 +182,22 @@ object MainForm: TMainForm TabOrder = 14 OnClick = btnForEachWithExceptionClick end + object btnMap2: TButton + Left = 88 + Top = 27 + Width = 100 + Height = 30 + Caption = 'Map Enumerable' + TabOrder = 15 + OnClick = btnMap2Click + end + object btnMap2Array: TButton + Left = 88 + Top = 63 + Width = 100 + Height = 30 + Caption = 'Map Array' + TabOrder = 16 + OnClick = btnMap2ArrayClick + end end diff --git a/samples/higher_order_functions/MainFormU.pas b/samples/higher_order_functions/MainFormU.pas index 36c68227..5eb82f2a 100644 --- a/samples/higher_order_functions/MainFormU.pas +++ b/samples/higher_order_functions/MainFormU.pas @@ -51,6 +51,8 @@ type btnJustLoop: TButton; lbForEach: TListBox; btnForEachWithException: TButton; + btnMap2: TButton; + btnMap2Array: TButton; procedure btnMapAddStarsClick(Sender: TObject); procedure btnReduceSumClick(Sender: TObject); procedure btnFilterBetwenClick(Sender: TObject); @@ -62,6 +64,8 @@ type procedure btnMapCapitalizeClick(Sender: TObject); procedure btnJustLoopClick(Sender: TObject); procedure btnForEachWithExceptionClick(Sender: TObject); + procedure btnMap2Click(Sender: TObject); + procedure btnMap2ArrayClick(Sender: TObject); private procedure FillList(Data: TArray; AStrings: TStrings); overload; procedure FillList(Data: TArray; AStrings: TStrings); overload; @@ -74,6 +78,9 @@ var implementation +uses + System.Generics.Collections; + {$R *.dfm} @@ -170,6 +177,57 @@ begin end); end; +procedure TMainForm.btnMap2ArrayClick(Sender: TObject); +begin + lbMap.Clear; + var lInput: TArray; + + SetLength(lInput, 10); + for var I := 1 to Length(lInput) do + begin + lInput[I-1] := I * 10; + end; + + var lListOfStr := HigherOrder.Map( + lInput, function(const Item: Integer): String + begin + Result := '**' + Item.ToString; + end); + try + lbMap.Items.AddStrings(lListOfStr.ToArray); + finally + lListOfStr.Free; + end; +end; + +procedure TMainForm.btnMap2Click(Sender: TObject); +begin + lbMap.Clear; + var lList := TList.Create; + try + for var lControl in Self.GetControls([ceftEnabled]) do + begin + if lControl is TButton then + begin + lList.Add(TButton(lControl)); + end; + end; + + var lListOfStr := HigherOrder.Map( + lList, function(const Item: TButton): String + begin + Result := String(Item.Caption).ToUpper; + end); + try + lbMap.Items.AddStrings(lListOfStr.ToArray); + finally + lListOfStr.Free; + end; + finally + lList.Free; + end; +end; + procedure TMainForm.btnMapAddStarsClick(Sender: TObject); var InputData, OutputData: TArray; diff --git a/sources/MVCFramework.Utils.pas b/sources/MVCFramework.Utils.pas index 628fa5aa..c15ff438 100644 --- a/sources/MVCFramework.Utils.pas +++ b/sources/MVCFramework.Utils.pas @@ -30,7 +30,8 @@ interface uses MVCFramework.Serializer.Commons, JsonDataObjects, - MVCFramework.DuckTyping, System.Classes, System.SysUtils; + MVCFramework.DuckTyping, System.Classes, System.SysUtils, + System.Generics.Collections; type EHOError = class(Exception) @@ -54,19 +55,27 @@ type end; TMapClosure = reference to function(const Item: T): T; + TMapClosure2 = reference to function(const Item: T1): T2; TForEachClosure = reference to procedure(const Item: T); TMapReduceClosure = reference to function(const Left: T; const Right: T): T; TPredicateClosure = reference to function(const Item: T): Boolean; HigherOrder = class sealed + public class function Map(const InputArray: TArray; - const MapClosure: TMapClosure): TArray; + const MapClosure: TMapClosure): TArray; overload; + class function Map(const List: TEnumerable; + const MapClosure: TMapClosure2): TList; overload; + class function Map(const InputArray: TArray; + const MapClosure: TMapClosure2): TList; overload; class function Reduce(const InputArray: TArray; const ReduceFunction: TMapReduceClosure; InitValue: T): T; class function Filter(const InputArray: TArray; const FilterFunction: TPredicateClosure): TArray; class procedure ForEach(const InputArray: TArray; - const ForEachClosure: TForEachClosure); + const ForEachClosure: TForEachClosure); overload; + class procedure ForEach(const Enumerable: TEnumerable; + const ForEachClosure: TForEachClosure); overload; end; function NewJSONSerializer: IMVCJSONSerializer; @@ -87,7 +96,6 @@ uses IdHashMessageDigest, IdHashSHA, {$ENDIF} - System.Generics.Collections, MVCFramework.Serializer.JsonDataObjects, MVCFramework.Commons, System.TypInfo; @@ -241,6 +249,78 @@ begin end; end; +class procedure HigherOrder.ForEach(const Enumerable: TEnumerable; const ForEachClosure: TForEachClosure); +var + lIdx: Integer; + lItem: T; +begin + lIdx := 0; + try + for lItem in Enumerable do + begin + ForEachClosure(lItem); + Inc(lIdx); + end; + except + on E: Exception do + begin + raise EHOForEachError.CreateFmt + ('ForEach error at element %d - [Class: %s][Message: %s]', + [lIdx, E.ClassName, E.Message]); + end; + end; +end; + +class function HigherOrder.Map(const List: TEnumerable; const MapClosure: TMapClosure2): TList; +var + lIdx: Integer; + lItem: T1; +begin + Result := nil; + lIdx := 0; + try + Result := TList.Create; + for lItem in List do + begin + Result.Add(MapClosure(lItem)); + Inc(lIdx); + end; + except + on E: Exception do + begin + Result.Free; + raise EHOMapError.CreateFmt + ('Map error at index %d - [Class: %s][Message: %s]', + [lIdx, E.ClassName, E.Message]); + end; + end; +end; + +class function HigherOrder.Map(const InputArray: TArray; const MapClosure: TMapClosure2): TList; +var + lIdx: Integer; + lItem: T1; +begin + Result := nil; + lIdx := 0; + try + Result := TList.Create; + for lItem in InputArray do + begin + Result.Add(MapClosure(lItem)); + Inc(lIdx); + end; + except + on E: Exception do + begin + Result.Free; + raise EHOMapError.CreateFmt + ('Map error at index %d - [Class: %s][Message: %s]', + [lIdx, E.ClassName, E.Message]); + end; + end; +end; + class function HigherOrder.Map(const InputArray: TArray; const MapClosure: TMapClosure): TArray; var