David Schwartz 426 Posted October 19, 2020 (edited) Just for fun, I thought I'd post this here. I have four TMemos on a form into which users can enter some lines of text, usually not more than 5 lines, but that's just a guideline. Let's call them m1, m2, m3, and m4. There's a field where they can specify a "delimiter" like a space, comma, hyphen, underscore, ampersand, etc. Write a method that creates a list of strings in an output TMemo composed of all possible combinations of lines from each of the four TMemos left-to-right (1+2+3+4) with the "delimiter" inserted between each one. So you get something like rsltmemo.Add( m1.Lines[i]+delim+m2.Lines[j]+delim+m3.Lines[k]+delim+m4.Lines[n] ); where each Lines index is in the range [0..Lines.Count-1] for that memo. For me, the obvious approach was four nested loops. Then someone suggested, "Why not just have an [+Add] button that lets you add as many of these boxes [ie., input TMemos] as you want?" The challenge is to write a method to generate the output from some 'n' input TMemos in as few statements as possible? Right off the bat, I can think of at least four different ways to do it, and more if there are things in the VCL libs that might help that I'm not aware of. (I have a feeling a good functional programming lib would let you do it in just a few statements for an arbitrary number of input TMemos.) Edited October 19, 2020 by David Schwartz Share this post Link to post
Uwe Raabe 2057 Posted October 19, 2020 For one memo the result is just that memo. Given the result for n memos, the result for adding another memo is just the combination of that result with the new memo. procedure Combine(Source, Target: TStrings; const Delimiter: string = ';'); var lst: TStringList; S: string; T: string; begin if Target.Count = 0 then begin Target.Assign(Source); end else begin lst := TStringList.Create(); try for S in Source do for T in Target do lst.Add(T + Delimiter + S); Target.Assign(lst); finally lst.Free; end; end; end; The calling part could look like this: var A: TStringList; memo: TMemo; begin A := TStringList.Create; try for memo in [memo1, memo2, memo3] do Combine(memo.Lines, A); memResult.Lines := A; finally A.Free; end; end; 1 Share this post Link to post
aehimself 396 Posted October 20, 2020 Just store the TMemos in a TList when you create them so you don't have to find them later. When generating; have two nested cycles going through that list. Outer from Low(list) To High(list) - 1; inner from outer var to High(list). Not efficient, but easy enough to understand what is going on. 1 Share this post Link to post
Guest Posted November 14, 2020 (edited) On 10/18/2020 at 11:38 PM, David Schwartz said: Just for fun, I thought I'd post this here. ... (I have a feeling a good functional programming lib would let you do it in just a few statements for an arbitrary number of input TMemos.) Maybe some like this: var Form1: TForm1; implementation {$R *.dfm} const lDelimiter: string = '#'; procedure TForm1.Button2Click(Sender: TObject); begin prcJoinMemosLinesWithDelimiter([Memo1, Memo2, Memo3, Memo4], 2); end; procedure TForm1.prcJoinMemosLinesWithDelimiter(lMemos: array of TMemo; lOnlyNLines: integer); var lLine : integer; lMyMemo: TMemo; begin for lMyMemo in lMemos do begin for lLine := 0 to Pred(lOnlyNLines) do Memo5.Lines.Add(lMyMemo.Lines[lLine]); // or ..Lines[lLine] + lDelimiter ); for each line // using "Add()" because the "lOnlyNLines" context // // Memo5.Lines.Add(lDelimiter); end; end; Edited November 14, 2020 by Guest Share this post Link to post
balabuev 102 Posted November 15, 2020 (edited) procedure CombineMemos(const AMemos: array of TMemo; ADelimiter: Char; AResult: TMemo); var i, cnt: Integer; rem: UInt64; idx: UInt64; mm: TMemo; s: string; begin cnt := Ord(Length(AMemos) > 0); for mm in AMemos do cnt := cnt * mm.Lines.Count; for i := 0 to cnt - 1 do begin s := ''; rem := i; for mm in AMemos do begin DivMod(rem, mm.Lines.Count, rem, idx); s := s + IfThen(mm <> AMemos[0], ADelimiter, '') + mm.Lines[idx]; end; AResult.Lines.Add(s); end; end; Edited November 15, 2020 by balabuev Share this post Link to post
Guest Posted November 16, 2020 5 hours ago, balabuev said: procedure CombineMemos(const AMemos: array of TMemo; ADelimiter: Char; AResult: TMemo); var ... begin ... s := s + IfThen(mm <> AMemos[0], ADelimiter, '') + mm.Lines[idx]; ... end; This line, in RAD 10.3.3 and RAD 10.4.1 show an error on "Params" of IfThen() function And, if any Memo contain 1 line more than others, the content will be repeated on final resulted until all than all memo having same number lines!!! Share this post Link to post
balabuev 102 Posted November 16, 2020 (edited) Everything works ok. You have to use Math and StrUtils units. Edited November 16, 2020 by balabuev Share this post Link to post
Guest Posted November 16, 2020 (edited) if was said before... about "StrUtils". I used just "Math". ok I'll try later. thanks Edited November 16, 2020 by Guest Share this post Link to post
Guest Posted November 17, 2020 (edited) On 11/16/2020 at 3:14 AM, balabuev said: Everything works ok. You have to use Math and StrUtils units. ... MATH and STRSYSTEM units added, but the same resulted: Edited November 17, 2020 by Guest Share this post Link to post
Guest Posted November 17, 2020 (edited) maybe this will be better than my first sample: function TForm1.fncJoinMemosLinesWithDelimiter(lMemos: array of TMemo; lOnlyNLines: integer; lDelimiter: Char = '#'): string; var lMyMemo : TMemo; lEachLine: string; begin for lMyMemo in lMemos do begin for lEachLine in lMyMemo.Lines do begin if ((lMyMemo.Lines.IndexOf(lEachLine) - 1) > lOnlyNLines) then break; // result := result + lEachLine + lDelimiter; end; end; end; procedure TForm1.btnMyCodeClick(Sender: TObject); begin Memo5.Lines.Add( { } fncJoinMemosLinesWithDelimiter([Memo1, Memo2, Memo3, Memo4], 2) { } ); end; hug Edited November 17, 2020 by Guest Share this post Link to post
balabuev 102 Posted November 17, 2020 (edited) I think you misunderstood the initial task... On 10/19/2020 at 5:38 AM, David Schwartz said: Write a method that creates a list of strings in an output TMemo composed of all possible combinations of lines from each of the four TMemos left-to-right (1+2+3+4) with the "delimiter" inserted between each one. Edited November 17, 2020 by balabuev Share this post Link to post
Guest Posted November 17, 2020 1 hour ago, balabuev said: I think you misunderstood the initial task... you can be right! sorry my point! Share this post Link to post