VBA to Concatenate Variable Range

Leopard011

New Member
Joined
Oct 24, 2012
Messages
3
Dear All,
I have a problem with a worksheet that my company accounting system exports every month.

Below is the download link of sample of the worksheet because I wasn't able to attach it to this thread.
vba.xlsx

In column ( F ) , I need a macro to do the following calculations:
1- Check for the Title – if it begins with "Cost Center"
2- Check for the Title – if it begins with "Account Code"
3- Detect the Range Start just below "Account Code" , and End with the row above "Total"
4- Concatenate the string written in each row of the range with the string in "Cost Center"

The Story is:
Each Month I've this worksheet with hundreds of Cost Centers and subsidiary Account Codes, And to be able to analyze the accounts efficiently I need to concatenate both Cost Centers & Account Codes manually ( as you see coloring sample in the sample file ).
Which led to wasting many hours , and high risk of error while copying and pasting formulas.

Your help on this matter will be highly appreciated.
Best Regards.
 

Excel Facts

What did Pito Salas invent?
Pito Salas, working for Lotus, popularized what would become to be pivot tables. It was released as Lotus Improv in 1989.
Provide some sample data to work with?
 
Upvote 0
Sorry don't know how to do everything vba but very nice question. Hopefully, Excel MVP can step in and help here.

Biz
 
Upvote 0
Try code below.

It maybe not most efficent way to handle this problem. Hoping someone can direct to a better way.

Code:
Dim wsTarget As Worksheet, LR As Long
Sub Test()
Dim aStartTime
    
    'Speeding Up VBA Code
    With Application
        .ScreenUpdating = False 'Prevent screen flickering
        '.Calculation = xlCalculationManual 'Preventing calculation
        .DisplayAlerts = False 'Turn OFF alerts
        .EnableEvents = False 'Prevent All Events
    End With
    
    'Start Timer
    aStartTime = Now()
'Set Variables
Set wsTarget = Sheets("Sheet1") '<<== Change as Required
'Get Last Row in Destination sheet
 LR = wsTarget.Cells(Rows.Count, "A").End(xlUp).Row

'Run Vba now
Call Mix1
Call Mix2
Call Mix3
'Remove fixed address
  wsTarget.Columns("F:F").Replace What:="$", Replacement:="", LookAt:=xlPart, _
        SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
        ReplaceFormat:=False
'Fill in blanks in Col E
On Error Resume Next
    With wsTarget.Range("E5:E" & LR).SpecialCells(xlCellTypeBlanks)
        .FormulaR1C1 = "=R[-1]C"
    End With
On Error GoTo 0
    'Clears Clipboard
    Application.CutCopyMode = False
    
    'Paste Special as Values
    With wsTarget.Range("E5:E" & LR)
         .Value = .Value
    End With
        
'Fill in blanks with cell addresses
Dim rCells As Range, Rng As Range
Set Rng = wsTarget.Range("F7:F" & LR)
For Each rCells In Rng
rCells.Formula = "A" & rCells.Row
Next rCells
'------------------------------------
'Copy Formulas
Dim fArray As Variant, eArray As Variant
Dim r As Long, z As Long
eArray = wsTarget.Range("E8:E" & LR).Value
fArray = wsTarget.Range("F8:F" & LR).Value
r = 8
For z = 1 To UBound(eArray)
On Error Resume Next
wsTarget.Range("G" & r).Formula = "=" & fArray(z, 1) & "&" & eArray(z, 1)
On Error GoTo 0
r = r + 1
Next z
'-------------------------------
'Tidy up by deleting unnecessary formulas
Dim FilterRng As Range, FilterRngClear As Range
Set FilterRng = wsTarget.Range("$A$7:$G$" & LR)
Set FilterRngClear = FilterRng.Offset(1, 4).Resize(FilterRng.Rows.Count - 1, 3)
'Removes AutoFilter if one exists
wsTarget.AutoFilterMode = False
With FilterRng
.AutoFilter Field:=1, Criteria1:="Account Code"
    FilterRngClear.SpecialCells(xlCellTypeVisible).ClearContents 'Clears Range("E8:G50").visible cells only
.AutoFilter Field:=1, Criteria1:="Account Code"
    FilterRngClear.SpecialCells(xlCellTypeVisible).ClearContents 'Clears Range("E8:G50")
.AutoFilter Field:=1, Criteria1:="Total"
    FilterRngClear.SpecialCells(xlCellTypeVisible).ClearContents 'Clears Range("E8:G50")
.AutoFilter Field:=1, Criteria1:="="
    FilterRngClear.SpecialCells(xlCellTypeVisible).ClearContents 'Clears Range("E8:G50")
.AutoFilter Field:=1, Criteria1:="*Cost*"
    FilterRngClear.SpecialCells(xlCellTypeVisible).ClearContents 'Clears Range("E8:G50")
End With
'Removes AutoFilter if one exists
wsTarget.AutoFilterMode = False
With wsTarget
.Columns("F:F").Delete Shift:=xlToLeft
.Columns("E:E").ClearContents
.Columns("F:F").EntireColumn.AutoFit
End With
    
'Release memory
    Set wsTarget = Nothing
    Set Rng = Nothing
    Set FilterRng = Nothing
    Set FilterRngClear = Nothing
    
    'Speeding Up VBA Code
    With Application
        .ScreenUpdating = True 'Prevent screen flickering
        '.Calculation = xlAutomatic 'Preventing calculation
        .DisplayAlerts = True 'Turn OFF alerts
        .EnableEvents = True 'Prevent All Events
    End With
    
    'End Timer
    MsgBox "Time taken: " & Format(Now() - aStartTime, "h:mm:ss"), vbInformation, "Job Done"
    
End Sub
 
Sub Mix1()
' For All Matching Values in Second Column
' Add 'X' to Column D
Dim arTemp() As String 'Temp Array
Dim bFound As Boolean 'Flag
Dim i1 As Integer 'Array Counter
Dim List As Variant
Dim arList() As String 'Temp Array
Dim i2 As Integer 'Array Counter
Dim j As Integer
 
 bFound = FindAll("Cost Center", wsTarget, "A1:A" & LR, arTemp())
 
If bFound = True Then
 For i1 = 1 To UBound(arTemp)
 ' The Row Number Can be used for extracting data
 ActiveSheet.Range(arTemp(i1)).Offset(0, 4).Value = arTemp(i1)
 Next i1
 Else
 MsgBox "Search Text Not Found"
 End If
 
End Sub
Sub Mix2()
' For All Matching Values in Second Column
' Add 'X' to Column D
Dim arTemp() As String 'Temp Array
Dim bFound As Boolean 'Flag
Dim i1 As Integer 'Array Counter
Dim List As Variant
Dim arList() As String 'Temp Array
Dim i2 As Integer 'Array Counter
Dim j As Integer
 
 bFound = FindAll("Account Code", wsTarget, "A1:A" & LR, arTemp())
 
If bFound = True Then
 For i1 = 1 To UBound(arTemp)
 ' The Row Number Can be used for extracting data
 ActiveSheet.Range(arTemp(i1)).Offset(1, 5).Value = arTemp(i1)
 Next i1
 Else
 MsgBox "Search Text Not Found"
 End If

End Sub
Sub Mix3()
' For All Matching Values in Second Column
' Add 'X' to Column D
Dim arTemp() As String 'Temp Array
Dim bFound As Boolean 'Flag
Dim i1 As Integer 'Array Counter
Dim List As Variant
Dim arList() As String 'Temp Array
Dim i2 As Integer 'Array Counter
Dim j As Integer
 
 bFound = FindAll("Total", wsTarget, "A1:A" & LR, arTemp())
 
If bFound = True Then
 For i1 = 1 To UBound(arTemp)
 ' The Row Number Can be used for extracting data
 ActiveSheet.Range(arTemp(i1)).Offset(-1, 5).Value = arTemp(i1)
 Next i1
 Else
 MsgBox "Search Text Not Found"
 End If

End Sub


Function FindAll(ByVal sText As String, ByRef oSht As Worksheet, ByRef sRange As String, ByRef arMatches() As String) As Boolean
' --------------------------------------------------------------------------------------------------------------
' FindAll - To find all instances of the1 given string and return the row numbers.
' If there are not any matches the function will return false
' --------------------------------------------------------------------------------------------------------------
 
On Error GoTo Err_Trap
Dim rFnd As Range ' Range Object
Dim iArr As Integer ' Counter for Array
Dim rFirstAddress ' Address of the First Find
' -----------------
' Clear the Array
' -----------------
Erase arMatches
Set rFnd = oSht.Range(sRange).Find(What:=sText, LookIn:=xlValues, LookAt:=xlPart)
If Not rFnd Is Nothing Then
 rFirstAddress = rFnd.Address
 Do Until rFnd Is Nothing
 iArr = iArr + 1
 ReDim Preserve arMatches(iArr)
 arMatches(iArr) = rFnd.Address ' rFnd.Row ' Store the Row where the text is found
 Set rFnd = oSht.Range(sRange).FindNext(rFnd)
 If rFnd.Address = rFirstAddress Then Exit Do ' Do not allow wrapped search
 Loop
 FindAll = True
Else
 ' ----------------------
 ' No Value is Found
 ' ----------------------
 FindAll = False
End If

' -----------------------
' Error Handling
' -----------------------
Err_Trap:
If Err <> 0 Then
 MsgBox Err.Number & " " & Err.Description, vbInformation, "Find All"
 Err.Clear
 FindAll = False
 Exit Function
End If
End Function
 
Upvote 0
Welcome to MrExcel Board, Leopard011 !
Try this code too:
Rich (BB code):
Sub ConcatCode()
 
  '--> Settings, change to suit
  Const SrcColumn = "A"
  Const DestColumn = "H"
  Const CenterMask = "Cost Center Code:"
  Const DataTop = "Account Code"
  Const DataBottom = "Total"
  ' <-- End of settings
 
  Dim a, b(), CenterCode As String, IsConcat As Boolean, r As Long, Rng As Range, v
 
  ' Define the source range Rng
  Set Rng = Intersect(Columns(SrcColumn).Cells, ActiveSheet.UsedRange)
  If Rng Is Nothing Then MsgBox "Column " & SrcColumn & " is empty", vbExclamation, "Nothing to do"
 
  ' Trap errors
  On Error GoTo exit_
 
  ' Copy Rng's values to array to speed up processing
  a = Rng.Value
  If Not IsArray(a) Then ReDim a(1, 1): a = Rng.Value
  ReDim b(1 To UBound(a), 1 To 1)
 
  ' Main
  For r = 1 To UBound(a)
    v = a(r, 1)
    If VarType(v) = vbString Then
      If IsConcat Then
        If StrComp(v, DataBottom, vbTextCompare) = 0 Then
          ' DataBottom is found
          IsConcat = False
        Else
          ' Concatenate Account Code with Cost Center Code
          b(r, 1) = a(r, 1) & " " & CenterCode
        End If
      ElseIf StrComp(v, DataTop, vbTextCompare) = 0 Then
        ' DataTop is found
        IsConcat = True
      ElseIf InStr(1, v, CenterMask, vbTextCompare) = 1 Then
        ' Set code of the center
        CenterCode = v
        IsConcat = False
      End If
    End If
  Next
 
  ' Copy result to destination
  Columns(DestColumn).Value = b()
 
exit_:
  If Err Then MsgBox Err.Description, vbCritical, "ConcatCode Error"
 
End Sub
Regards
 
Last edited:
Upvote 0
Welcome to MrExcel Board, Leopard011 !
Try this code too:
Rich (BB code):
Sub ConcatCode()
 
  '--> Settings, change to suit
  Const SrcColumn = "A"
  Const DestColumn = "H"
  Const CenterMask = "Cost Center Code:"
  Const DataTop = "Account Code"
  Const DataBottom = "Total"
  ' <-- End of settings
 
  Dim a, b(), CenterCode As String, IsConcat As Boolean, r As Long, Rng As Range, v
 
  ' Define the source range Rng
  Set Rng = Intersect(Columns(SrcColumn).Cells, ActiveSheet.UsedRange)
  If Rng Is Nothing Then MsgBox "Column " & SrcColumn & " is empty", vbExclamation, "Nothing to do"
 
  ' Trap errors
  On Error GoTo exit_
 
  ' Copy Rng's values to array to speed up processing
  a = Rng.Value
  If Not IsArray(a) Then ReDim a(1, 1): a = Rng.Value
  ReDim b(1 To UBound(a), 1 To 1)
 
  ' Main
  For r = 1 To UBound(a)
    v = a(r, 1)
    If VarType(v) = vbString Then
      If IsConcat Then
        If StrComp(v, DataBottom, vbTextCompare) = 0 Then
          ' DataBottom is found
          IsConcat = False
        Else
          ' Concatenate Account Code with Cost Center Code
          b(r, 1) = a(r, 1) & " " & CenterCode
        End If
      ElseIf StrComp(v, DataTop, vbTextCompare) = 0 Then
        ' DataTop is found
        IsConcat = True
      ElseIf InStr(1, v, CenterMask, vbTextCompare) = 1 Then
        ' Set code of the center
        CenterCode = v
        IsConcat = False
      End If
    End If
  Next
 
  ' Copy result to destination
  Columns(DestColumn).Value = b()
 
exit_:
  If Err Then MsgBox Err.Description, vbCritical, "ConcatCode Error"
 
End Sub
Regards


Very nicely down mate. Can't believe the code is so compact. Another Gem.

Biz
 
Upvote 0
Dear ZVI;

The code worked successfully.
Thanks a million.

Now I can simply modify DestColumn to be any column in the sheet.
Also, considering ActiveSheet instead of certain Sheet Name is a brilliant idea for flexibility.

You are so helpful.

Best Regards
 
Upvote 0
Very nicely down mate. Can't believe the code is so compact. Another Gem.

Biz
Thanks for the response, Biz,
<o:p> </o:p>
For me any working code is good irrespective to its size
May be the compact one is a little easier in the analysis, but seems not always :)
For adjustment convenience I like to place settings in top of a code instead of correcting them in all code.
<o:p> </o:p>
Looking on my code again I've found a typo,
was: If Not IsArray(a) Then ReDim a(1, 1): a = Rng.Value
should be: IfNot IsArray(a) Then ReDim a(1, 1): a(1, 1) = Rng.Value
but ...Then Exit Sub would be even better.

Best Regards
 
Last edited:
Upvote 0
Thanks a million.

Now I can simply modify DestColumn to be any column in the sheet.
You are welcome, Leopard011;
And thank you for the feedback!

If destination column is varied then this:
Rich (BB code):
  ' Copy result to destination
  Columns(DestColumn).Value = b()
can be replaced by that:
Rich (BB code):
  ' Copy result to destination
  Dim Dest As Range
  On Error Resume Next
  Set Dest = Application.InputBox( _
        "Select any cell in destination column", _
        Default:=ActiveCell.Address, _
        Type:=8)
  Err.Clear
  If Not Dest Is Nothing Then Columns(Dest.Column).Value = b()

Cheers!
 
Last edited:
Upvote 0

Forum statistics

Threads
1,223,247
Messages
6,171,007
Members
452,374
Latest member
keccles

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top