2

It has been really frustrating experience for me trying to do mail merge (if I can call my requirement that). I have a word template doc that contains placeholders like {{JointHolder}} {{JointHolderPAN}} , {{Holding}}, {{Nominee}}, ₹ {{UndrawnCapital | number :”N0”}} Excel file contains sheet named "Mappings" which ahs mapping of these placeholders to header name.

This placeholder format is specific to my licensed tool. Now I shifted my attempt to python keeping these placeholders intact. Is VBA a better choice for my requirement?

I have reached to a point where placeholders are getting replaced with values from my excel file. But the actual formats of the placeholders are not preserved. For example, bold, font type, font size, superscript, left right center alignment. These formatting are critical to my requirement.

MAJOR ISSUE is that I need to generate table based upon a keyword "REPEAT" which is in the first cell of the row which needs to be repeated. This is not working.

Expected Table Output -

enter image description here

For minimum reproducible example - Link to the sample word template, excel file and python project .py file

Your guidance is highly appreciated.

Edit: I used this tool earlier - https://www.pdfmachine.com/pdfmachine-merge/. Now I want to get rid of this tool completely and hence trying python.

Edit: I have now switched to VBA as an experimentation. VBA macros file is in the shared folder. Link provided above.

Table generation requirement -

I have tables in the word template and most of the placeholders are inside tables. These could be nested tables as well.

  • There are rows which need to be repeated based upon if a 'y' is found in TableDisplayX column
  • The first cell of such a row contains the word "REPEAT" and "TableDisplayX" mandatorily, where X can be any integer like 1,2,3,4,5,6, etc.
  • TableDisplayX is a header in the MailMerge sheet it contains 'y' value if that particular row needs to be there in the generated table for that PATRTICULAR INVESTOR
  • Other cells in the same row contain 1 or more placeholders.
  • Values in the generated table will be fetched from the column with the headers represented by these placeholders
  • Take note that every row of this generated table will contain data from a different consecutive row from the MailMerge sheet corresponding to that investor.

To solve these generated table complexities I recommend that -

  • current code should stop replacing placeholders in the rows where the first cell contains "REPEAT" word

  • After normal replacement of placeholders, which is currently taken care by the program, the code should start finding table rows with "REPEAT" word

  • Handle each "REPEAT" row separately

  • Find the header corresponding to "TableDisplayX" where X is an integer e.g TableDisplay1 is a header in my MailMerge sheet

  • Find number of 'y' s in the field for that investor. This is the number of rows of data to be inserted

  • Find all the other headers in the same row in different cells

  • If for example number of 'y's is 5 then the repeating rows must be 5. These repeating rows must be exactly below the "REPEAT" row; including this row itself. so the newly inserted rows must be 4.

  • get data for that particular investor from all the headers and place in these table rows.

  • repeat above steps for other "REPEAT" rows

Shri
  • 156
  • 11
  • Not sure I would be able to help, but I couldn't see the .py file (I could see the Excel and Word files). – jonsson Jul 21 '23 at 11:11
  • In the sample document all the formatting has been directly applied to the text. If you want the formatting to persist when you update the data, you need to apply Styles to the table cells. – Timothy Rylatt Jul 21 '23 at 14:03
  • 1
    What exactly is your "licensed tool" and how does it fit into this process? It's not really that clear from your post exactly what the issue is. – Tim Williams Jul 21 '23 at 16:45
  • 3
    This *might* be easier to do using VBA - not sure how the python libraries for dealing with Word docs compare to the "native" VBA capabilities. Typically, setting `someRange.Text` will preserve the formatting applied to `someRange` (assuming that formatting is consistent across the whole range being updated) – Tim Williams Jul 25 '23 at 22:31
  • @TimWilliams I am now trying using VBA. I have uploaded my VBA file with the input excel file and word template. You can find the google drive link in the question above. I have solved the basic problem of replacing placeholders and formatting with VBA but the complex issue of generating table still persists. Could you please help. Thanks I have added additional details about the table in the question – Shri Jul 26 '23 at 06:53
  • Simpler now you moved the formatting to the mapping table... I will take a look later. – Tim Williams Jul 26 '23 at 15:10
  • @TimWilliams Thanks, I have also added codes to add rows for the table to be generated. Still generation of table needs completion and also the code takes a lot fo time to process. – Shri Jul 26 '23 at 17:20
  • `"TableDisplayX" where X is an integer e.g TableDisplay1 is a header in my MailMerge sheet` Now it's 2 not 1 anymore, right? `repeat above steps for other "REPEAT" rows` however there is only one in your sample, so what your real document has more `REPEAT` in it? – Oscar Sun Jul 27 '23 at 14:58
  • @OscarSun - I get the impression there could be multiple different "TableDisplayX" within the same document... – Tim Williams Jul 27 '23 at 14:59
  • @TimWilliams In my downloaded .docx file there is just one `TableDisplay2` in it. – Oscar Sun Jul 27 '23 at 15:02
  • In your .xlsm VBA code `InvestorName = wsMailMerge.Cells(r, 1).value ' Assuming column A contains the investor names` however it seems column G Name is the *investor names*, not column 1. Is that right? – Oscar Sun Jul 27 '23 at 15:13
  • 1
    Started from scratch so I will be late with any answer here... Will post a link if i get it working though. – Tim Williams Jul 28 '23 at 00:55
  • 1
    Too much code to post so linked here: https://drive.google.com/file/d/1soReUOxbJKVG5mp2o93GJREEXQpVWtSO/view?usp=sharing Still slow though ... One change - no quotes allowed in the tag which signifies a repeated row eg. `REPEAT TableDisplay2` and not `REPEAT "TableDisplay2"` – Tim Williams Jul 28 '23 at 21:52
  • @TimWilliams Thank you for your hard work and dedication. You should take this response as an answer so that the questioner can give his thanks to you. It is also more convenient for latecomers to refer to. – Oscar Sun Jul 29 '23 at 02:56
  • @OscarSun - I will see if the code fits in an answer. – Tim Williams Jul 30 '23 at 18:38
  • My APOLOGIES to everyone. I was out of town for sometime due to urgent work. Now, I will go through all the solutions provided in the next few days. Thanks everyone. – Shri Aug 02 '23 at 12:54

1 Answers1

1

OK try my code first. You see so far, if this is satisfactory for you?

Sub CreateDocuments()
    
    ' Define the workbook and worksheet
    Dim wb As Workbook
    Set wb = ThisWorkbook
    Dim wsMailMerge As Worksheet:    Set wsMailMerge = wb.Sheets("MailMerge")
    Dim wsMappings As Worksheet:    Set wsMappings = wb.Sheets("Mappings")
    
    Rem test to temply comment out
    Application.ScreenUpdating = False
    Application.Calculation = xlManual
    Application.DisplayAlerts = False
    
    ' Define the last row in the sheet
    Dim LastRow As Long
    LastRow = wsMailMerge.Cells(wsMailMerge.Rows.count, 1).End(xlUp).Row
    
    
    
    Dim WordApp As Object, myDoc As Object, wdRng As Object, TableHeader As String, placeholders As Object, tblREPEAT As Object
    Dim tbl As Object 'Word.Table
    Dim Find1 As Excel.Range, Find2 As Excel.Range, Find3 As Excel.Range, header As String
    Dim Timer2 As Single
    
    ' Open the Word application
    Set WordApp = CreateObject("Word.Application")
    WordApp.Visible = True
    
    Rem test to temply comment out
    WordApp.ScreenUpdating = False
    
    
    ' Define a Dictionary to store which investors have been processed
    Dim ProcessedInvestors As Object
    Set ProcessedInvestors = CreateObject("Scripting.Dictionary")
    
    
    Set placeholders = CreateObject("Scripting.Dictionary")
    
    ' Loop through each row in the MailMerge sheet
    Dim r As Long
    For r = 2 To LastRow ' Assuming your data starts from row 2 (row 1 contains headers)
        
        
        ' Get the name of the current investor
        Dim InvestorName As String
        InvestorName = wsMailMerge.Cells(r, 1).value ' Assuming column A contains the investor names
    
        ' Check if the investor has already been processed
        If Not ProcessedInvestors.Exists(InvestorName) Then
            ' Mark the investor as processed
            ProcessedInvestors.Add InvestorName, True
            
            ' Open the Word document
            Set myDoc = WordApp.Documents.Open(wb.Path & "\sample2 - Template SOA - Copy.docx") ' Use the workbook's path and the name of your Word template
            
            Rem get the Table include `REPEAT`
            For Each tbl In myDoc.Tables
                If InStr(tbl.Cell(2, 1).Range.Text, "REPEAT") > 0 Then
                    Rem  back up Placeholders in a row of the table
                    Rem use the clipboard, whilst the system needs the clipboard, causes a problem
'                    tbl.Rows(2).Range.Copy
'                    myDoc.Range(tbl.Cell(tbl.Rows.count, 1).Range.Start, tbl.Cell(tbl.Rows.count, 1).Range.Start).Paste
                    Rem implement without the clipboard
                    myDoc.Range(tbl.Cell(tbl.Rows.count, 1).Range.Start, tbl.Cell(tbl.Rows.count, 1).Range.Start).FormattedText = tbl.Rows(2).Range.FormattedText
                    Rem clear the `REPEAT"TableDisplay2"` in the backup row
                    Set wdRng = myDoc.Range(tbl.Cell(3, 1).Range.Start, tbl.Cell(3, 1).Range.Start)
                    wdRng.MoveUntil "{"
                    wdRng.Start = tbl.Cell(3, 1).Range.Start
                    wdRng.Text = vbNullString
                    Set tblREPEAT = tbl 'Store tables with variable tblREPEAT
                    'Exit For ' if only one table include `REPEAT`
                End If
            Next tbl
            
            ' Loop through each column in the row
            Dim c As Long
            
            Dim clumCount_wsMailMerge As Long: clumCount_wsMailMerge = wsMailMerge.Cells(r, Columns.count).End(xlToLeft).Column
            
            'For c = 1 To wsMailMerge.Cells(r, Columns.count).End(xlToLeft).Column
            For c = 1 To clumCount_wsMailMerge
                
'                If c = 176 Then Stop ' just for check
                
                
                Rem Your placeholder and the header of the wsMailMerge is NOT case-sensitive!!
                
                ' Define the placeholder and the value to replace it with
                Dim placeholder 'As String
                placeholder = "{{" & Trim(wsMailMerge.Cells(1, c).value) & "}}" ' The placeholder is the header in the Mappings sheet
                'placeholder = "{{" & Trim(wsMailMerge.Cells(1, c).Formula) & "}}" ' The placeholder is the header in the Mappings sheet
                
                
                'If placeholder = "{{Notes47}}" Then Stop 'just for check
'                If placeholder = "{{Address4}}" Then Stop 'just for check
        
                 Dim value As String
                    value = wsMailMerge.Cells(r, c).value ' The value is the cell value in the current row
                    'If Trim(wsMailMerge.Cells(1, c).value) = "SOADate" Then Stop
                    
                    
                    ' Check for special formatting instructions
                    Dim formatting As String
                    GoSub getFormat
                    
                    'If placeholder Like "*{{SOADate}}*" Then Stop
                    
    '                If value = vbNullString Then Stop 'just for test
                    
                    Set wdRng = myDoc.Content
                    
                    ' Replace the placeholders in the Word document with the values from the record
                    'With myDoc.Content.Find
                    With wdRng.Find
                        .Text = placeholder
                        '.Replacement.Text = value
                        
                        .Wrap = wdFindContinue
                        .MatchWholeWord = True
                        
                        '.Execute Replace:=wdReplaceAll
                        Do While .Execute()
                            Rem don't do this in the record rows of the table including `REPEAT"TableDisplay2"` this time
                            If .Found Then
                                If .Parent.InRange(myDoc.Range(tblREPEAT.Cell(2, 1).Range.Start, tblREPEAT.Cell(3, tblREPEAT.Columns.count).Range.End)) Then
                                    Exit Do
                                Else
                                    .Parent.Text = value  'ie. .Replacement.Text = value and preserve the format
                                End If
                            End If
                        Loop
                    End With
NextPlaceholder:
            Next c
            ''''''''''''''''''''''''''''''''''''''''''''''''''''''
            
               Timer2 = Timer()
            ' Loop through each table
            'Dim tbl As Table
            'Dim tbl As Object 'Word.Table
            
            For Each tbl In myDoc.Tables
                If InStr(tbl.Cell(2, 1).Range.Text, "REPEAT") > 0 Then
                'If tbl Is tblREPEAT Then
                'If tbl.Range.Start = tblREPEAT.Range.Start Then
                    
                    ' Initialize row counter
                    Dim rowCounter As Integer
                    rowCounter = 1
                    
                    Rem  must be without merged cells by this way
                    ' Loop through each row
                    'Dim rw As Object 'Word.Row
                    'For Each rw In tbl.Rows
                        ' Loop through each cell
                        Dim cel As Object 'Word.Cell
                        'For Each cel In rw.Cells
                        For Each cel In tbl.Range.Cells
                            ' Check if the cell contains "REPEAT"
                            If InStr(cel.Range.Text, "REPEAT") > 0 Then
                                ' Extract the "TableDisplayX" placeholder
                                Dim startPos As Integer
                                startPos = InStr(cel.Range.Text, "TableDisplay")
                                If startPos > 0 Then
                                    Rem if length of `X` is longer then 1 then this will be wrong
                                    'TableHeader = Mid(cel.Range.Text, startPos, 13) ' There are 13 characters in "TableDisplayX"
                                    
                                    TableHeader = Mid(cel.Range.Text, startPos, InStr(startPos, cel.Range.Text, ChrW(8221)) - startPos)   ' There are 13 characters in "TableDisplayX"
                                    
                                    Rem clear the `REPEAT"TableDisplay2"`
                                    Set wdRng = myDoc.Range(cel.Range.Start + startPos, cel.Range.Start + startPos)
                                    wdRng.MoveUntil ChrW(8221)
                                    wdRng.Start = cel.Range.Start
                                    wdRng.End = wdRng.End + 1
                                    wdRng.Text = vbNullString
                                
                                Else
                                    MsgBox "TableDisplay column not found", vbCritical
                                    
                                    Rem don't forget to restore
                                    'Exit Sub
                                    GoTo ExitSub
                                    
                                End If
                                
                                

                                
                                
                                Set Find2 = wsMailMerge.Range("1:1").Find(TableHeader, lookat:=xlWhole, LookIn:=xlFormulas)
                                ' Determine the number of 'y' values in the "TableDisplayX" column for the current investor
                                'Dim TableDisplayColumn As Range
                                Dim TableDisplayColumn As Excel.Range
                                'Set TableDisplayColumn = wsMailMerge.Range(Cells(2, Find2.Column), Cells(LastRow, Find2.Column)) ' Replace "TableDisplayX" with the actual column letter
                                Set TableDisplayColumn = wsMailMerge.Range(wsMailMerge.Cells(2, Find2.Column), wsMailMerge.Cells(LastRow, Find2.Column)) ' Replace "TableDisplayX" with the actual column letter
                                
                                Dim FolioColumn As Range
                                Set FolioColumn = wsMailMerge.Range("A2:A" & LastRow)
                
                                Dim count As Integer
                                count = Application.WorksheetFunction.CountIfs(TableDisplayColumn, "y", FolioColumn, InvestorName)
                                                                
'                                tbl.Cell(tbl.Rows.count, 1).Split NumColumns:=2
'                                tbl.Cell(tbl.Rows.count, 1).Width = tbl.Cell(tbl.Rows.count - 1, 1).Width
'                                tbl.Cell(tbl.Rows.count, 2).Width = tbl.Cell(tbl.Rows.count - 1, 2).Width
                                
                                If count > 1 Then
                                
                                    'tbl.Rows(tbl.Rows.count - 1).Range.Copy
                                    ' Insert (n-1) rows below the repeating row
                                    Dim i As Integer
                                    For i = 1 To count - 1 - 1
                                        'rw.Range.Rows.Add
                                        
                                        'myDoc.Range(tbl.Cell(3, 1).Range.Start, tbl.Cell(3, 1).Range.Start).Paste
                                        'tbl.Rows.Add tbl.Rows(tbl.Rows.count)
                                        
                                        Rem add new rows like the backup one
                                        myDoc.Range(tbl.Cell(tbl.Rows.count, 1).Range.Start, tbl.Cell(tbl.Rows.count, 1).Range.Start).FormattedText = tbl.Rows(3).Range.FormattedText
    
                                        
                                    Next i
                                    
                                    
                                    'just for test
    '                                tbl.Range.Document.Tables.Add tbl.Range.Document.Range(tbl.Cell(tbl.Rows.count, 1).Range.Start, tbl.Cell(tbl.Rows.count, 1).Range.Start), count - 1, tbl.Columns.count
                                    
                                    
    '                                tbl.Cell(tbl.Rows.count, 1).Merge tbl.Cell(tbl.Rows.count, 2)
                                    
                                    
                                    ' Populate the cells in the new table
                                    'Dim newRow As Row
                                    Dim newCell As Word.Cell
                                    Dim rowIndex As Integer
                                    Dim firstRow As Long
                                    
                                    firstRow = GetFirstRowWithY(TableDisplayColumn, FolioColumn, InvestorName)
                    
                                    rowIndex = 0
                                    'For Each newRow In tbl.Range.Rows
                                        'If rowCounter = count Then
                                            'For Each newCell In newRow.Range.Cells
                                            
                                            rowCounter = 0
                                            
                                            Rem `myDoc.Range(...).Cells` get the range of new cells
                                            For Each newCell In myDoc.Range(tbl.Range.Cells(6 + 1).Range.Start, tbl.Cell(count + 1, tbl.Columns.count).Range.End).Cells
                                                ' Define the placeholder and the value to replace it with
        '                                        Dim placeholder As String ' this already declare before
                                                If rowCounter = 0 Then
                                                    rowCounter = newCell.rowIndex
                                                ElseIf rowCounter < newCell.rowIndex Then
                                                    rowIndex = rowIndex + 1 ' Increment row counter
                                                    rowCounter = newCell.rowIndex
                                                End If
                                                If newCell.ColumnIndex = 1 Then
                                                    
                                                    With newCell.Range.Find
                                                        .ClearAllFuzzyOptions
                                                        .ClearFormatting
                                                        .Wrap = wdFindStop
                                                        .Forward = True
                                                        .MatchWildcards = True 'use Wildcards to find
                                                        .Text = "\{\{*\}\}"
                                                        Do While .Execute
                                                            If .Parent.End > newCell.Range.End Then Exit Do 'if over the range of curent cell then exit
                                                            Rem Take note of the placeholder and its Range
                                                            'placeholders.Add VBA.Mid(.Parent.Text, 3, VBA.Len(.Parent.Text) - 4), .Parent '3=len("{{")+1
                                                            placeholders.Add .Parent.Text, .Parent.Duplicate  '3=len("{{")+1
                                                        Loop
                                                    End With
                                                    
                                                Else
                                                    Rem Take note of the placeholder and its Range
                                                    placeholders.Add VBA.Left(newCell.Range.Text, VBA.Len(newCell.Range.Text) - 2), newCell.Range ' The placeholder is the header in the Mappings sheet
                                                End If
                                                                                                
                                                'Dim value As String ' Already declared!!
                                                For Each placeholder In placeholders.keys
                                                    'Set Find3 = wsMappings.Range("A:A").Find(placeholder, lookat:=xlWhole, LookIn:=xlValues)
                                                    Set Find3 = wsMappings.Range("A:A").Find(placeholder, lookat:=xlWhole, LookIn:=xlValues)
                                                    If Not Find3 Is Nothing Then
                                                        header = Find3.Offset(0, 1).value
                                                        'Set Find3 = wsMailMerge.Rows(1).Find(header, lookat:=xlWhole, LookIn:=xlFormulas)
                                                        Set Find3 = wsMailMerge.Range("1:1").Find(header, lookat:=xlWhole, LookIn:=xlFormulas)
                                                        value = wsMailMerge.Cells(firstRow + rowIndex + 1, Find3.Column).value ' The value is the cell value in the current row
                                                        ' Replace the placeholders in the Word document with the values from the record
                                                        'newCell.Range.Text = value
                                                        GoSub getFormat:
                                                        placeholders(placeholder).Text = value
                                                    End If
                                                Next placeholder
                                                placeholders.RemoveAll
                                            Next newCell
                                        'End If
'                                        rowIndex = rowIndex + 1
                                    'Next newRow
                                    
                                Else
                                    Rem if there is no more row
                                    tbl.Rows(3).Delete 'delete the backup placeholdere copy one
                                End If
'                                GoTo currentDocDone: ' if only one table include `REPEAT`
                                GoTo nextTable
                            End If
                            
                        Next cel
                        ' Increment row counter
                        'rowCounter = rowCounter + 1
                    'Next rw
                
'                Else
'                    GoTo nextTable
                End If
nextTable:
            Next tbl
    


currentDocDone:
    
             MsgBox "time = " & (Timer() - Timer2)
                    
            ''''''''''''''''''''''''''''''''''''''''''''''''''''''
            
            On Error Resume Next
            ' Save the Word document
            myDoc.SaveAs wb.Path & "\" & wsMailMerge.Cells(r, 1).value & ".docx" ' Use the workbook's path and the investor's name from column A
            
            Rem temply comment out for test
            'myDoc.Close SaveChanges:=False
            
            
            On Error GoTo 0
            
            If Err.Number <> 0 Then
                MsgBox "Word doc save error", vbExclamation
            End If
        
        End If
    Next r
    
    Rem You can not do it here, cause WordApp'll be referred to later
'     Close the Word application
'    WordApp.Quit
    


ExitSub:

    WordApp.ScreenUpdating = True
    
    Rem temply comment out for test
'   Close the Word application
'    WordApp.Quit


    Application.ScreenUpdating = True
    Application.Calculation = xlAutomatic
    Application.DisplayAlerts = True
    
Exit Sub

getFormat:
            Set Find1 = Nothing
            formatting = ""
            
            Set Find1 = wsMappings.Range("A:A").Find(placeholder, lookat:=xlWhole, LookIn:=xlValues)
            If Not Find1 Is Nothing Then
                formatting = Find1.Offset(0, 2).value
            Else
                GoTo NextPlaceholder
            End If
            
            'If Not IsError(formatting) Then
            If formatting <> vbNullString And Not IsError(formatting) And formatting <> "SuperScript" Then
            
                Select Case formatting
                    Case "MMMM dd, yyyy"
                        value = Format(value, "MMMM dd, yyyy")
                    Case "N0"
                        value = Format(value, "#,##0")
                    Case "N1"
                        value = Format(value, "#,##0.0")
                    Case "N2"
                        value = Format(value, "#,##0.00")
                    Case "N3"
                        value = Format(value, "#,##0.000")
                    Case "N4"
                        value = Format(value, "#,##0.0000")
                    Case "P0"
                        value = Format(value, "0%")
                    Case "P1"
                        value = Format(value, "0.0%")
                    Case "P2"
                        value = Format(value, "0.00%")
                    Case "P3"
                        value = Format(value, "0.000%")
                    Case "P4"
                        value = Format(value, "0.0000%")
                    Case "NewLine"
                    
                        If value <> vbNullString Then
                            'value = value & Chr(10)
                            
                            value = Chr(10) & value
                        End If
                        
                    Case "SuperScript"
                        ' Handle superscript here
                End Select

    
            End If
            Return
End Sub

Your code and samples still have many problems and unclear points. You can only judge whether this is what you want. I just try to cooperate with the code you wrote to achieve it as much as possible.

It seems that your code and samples are still experiencing some issues and unclear aspects. It's up to you to determine if this is exactly what you are looking for. My goal is to work alongside the code you have written to do my best to achieve the desired outcome. Good luck! Ps. If I had time I will try to see how to do it in Python.

Oscar Sun
  • 1,427
  • 2
  • 8
  • 13
  • 1
    You could improve greatly the runtime by treating the `wsMailMerge` as a range and declare an array equal to it, then for `2 to UBound ` of it have `Dim InvestorName() As String : InvestorName(counter) = ` and so on for the others as well. And use `Value2` instead of `Value` (https://stackoverflow.com/a/37691997/18247317) (but now I see above some formatting must be kept, so maybe not this.) – Oran G. Utan Jul 29 '23 at 08:20
  • @Bradipo Thank you for your suggestions for optimization of the code. I just rewrote the code of the questioner first to achieve the results he wanted. As for the follow-up, I haven't received a reply from the questioner, so I stopped it first. Please excuse me. If there is further rewriting, I will include your suggestions into consideration. Thank you very much for your enthusiastic advice. – Oscar Sun Jul 29 '23 at 09:47
  • @Bradipo After I rewrote the code required and given by the questioner, I found that your suggestion is completely feasible. He only reads the value in the Excel file, so we can use arrays and `. Value2` totally, don't need to care about the format in the cells in the Excel file. His format requirements are completely placed in Word files. Perhaps rewrite with .Value2 and arrays, could be handed over to you, how about that? Oh hehe. Thank you. – Oscar Sun Jul 29 '23 at 10:02
  • 1
    I only thought about the speed (one of my main concerns as I normally have to work with large volumes of data, hence my fixation with arrays...). After I saw this video I changed a lot of my way of coding, I may overuse arrays, but with table kind of data I think they are the best solution https://www.youtube.com/watch?v=GCSF5tq7pZ0 – Oran G. Utan Jul 29 '23 at 10:21
  • the formatting could be either copy/pasted https://stackoverflow.com/a/43112452/18247317 or... well another array ahahaha but I mean that the cloning of values and that of the formatting do not necessarily have to happen in the same process, they could be split. – Oran G. Utan Jul 29 '23 at 13:32
  • My APOLOGIES to everyone. I was out of town for sometime due to urgent work. Now, I will go through all the solutions provided in the next few days. Thanks everyone. – Shri Aug 02 '23 at 12:57