OzGrid

How to use a macro to find value in a range of cells and combine values

< Back to Search results

 Category: [Excel]  Demo Available 

How to use a macro to find value in a range of cells and combine values

 

Requirement:

 

The user is trying to create a macro which will find the same value in a range of cells and combine values from another cells and seperate them by semicolon.


In column L the user has an order number and in column M there is a surname. If order number appear more than once there is a # at the end and a number (i.e 123#2), in such cases surname should be copied into first cell in column M next to duplicated order number.

E.g. the original data:

Column L Column M
65984 Smith
123#2 Doe
123 Birsack
89416 Lynch
8412 Wall
123#3 White
89416#2 Yellow
132 Brown


This is what the user is trying to achieve:

Column L Column M
65984 Smith
123#2 Doe; Birsack; White
123 Birsack
89416 Lynch;Yellow
8412 Wall
123#3 White
89416#2 Yellow
132 Brown

 

https://www.ozgrid.com/forum/forum/help-forums/excel-vba-macros/149853-macro-to-find-value-in-a-range-of-cells-and-combine-values

 

Solution:

 

Run this with that sheet active.

Code:
'solution similar to, http://www.ozgrid.com/forum/showthread.php?t=205473
Sub Main()
  Dim rS As Range, rT As Range, c As Range, f As Range
  Dim f1 As Range, f2 As Range
  'Add Tools > References > Microsoft Scripting Runtime
  Dim d As New Dictionary, e
  Dim a1(), a2(), b1(), b2(), u(), i As Integer, s As String
  
  Application.EnableEvents = False
  Application.Calculation = xlCalculationManual
  Application.ScreenUpdating = False
  Application.DisplayAlerts = False
  'On Error GoTo EndSub
  
  'Set column L and M ranges and working arrays.
  Set rS = Range("L2", Range("L2").End(xlDown))
  a1 = WorksheetFunction.Transpose(rS.Value)
  a2 = a1
  Set rT = Range("M2", Range("M2").End(xlDown))
  b1 = WorksheetFunction.Transpose(rT.Value)
  b2 = b1

  'Remove # suffix from column L.
  For i = 1 To rS.Cells.Count
   a2(i) = Split(a2(i), "#")(0) 'Remove # suffix
  Next i
  'Write back column L values without # suffixes.
  rS.Value = WorksheetFunction.Transpose(a2)
  
  'Make a2 values unique.
  u() = UniqueArrayByDict(a2())
  
  'Store unique values into dictionary.
  For i = 1 To UBound(u)
    d.Add u(i), Nothing
  Next i
  
  'Iterate column L values without suffixes.
  For i = 1 To UBound(a2)
    s = ""
    Set f1 = FindAll(rS, a2(i), xlValues, xlWhole, xlByRows, False)
    b2(i) = b1(i)
    If f1.Cells.Count > 1 And d.Exists(a2(i)) Then
      For Each c In f1.Offset(, 1)
        s = s & c.Value & "; "
      Next c
      s = Left(s, Len(s) - 2)
      b2(i) = s
    End If
    If d.Exists(a2(i)) Then d.Remove (a2(i))
  Next i
  
  'Write back column L values with # suffixes.
  rS.Value = WorksheetFunction.Transpose(a1)
  
  'Write back column M values with first unique group join.
  rT.Value = WorksheetFunction.Transpose(b2)
  
EndSub:
  Application.EnableEvents = True
  Application.Calculation = xlCalculationAutomatic
  Application.ScreenUpdating = True
  Application.DisplayAlerts = True
End Sub


 'https://msdn.microsoft.com/en-us/library/system.collections.arraylist(v=vs.110).aspx
Function advArrayListSort(sn As Variant, Optional tfAscending1 As Boolean = True, _
    Optional tfAscending2 As Boolean = True, _
    Optional tfNumbersFirst As Boolean = True) As Variant
     
    Dim i As Long, c1 As Object, c2 As Object
    Dim a1() As Variant, a2() As Variant, a() As Variant
     
    Set c1 = CreateObject("System.Collections.ArrayList")
    Set c2 = CreateObject("System.Collections.ArrayList")
     
    For i = LBound(sn) To UBound(sn)
        If IsNumeric(sn(i)) = True Then
            c1.Add sn(i)
        Else
            c2.Add sn(i)
        End If
    Next i
     
    c1.Sort 'Sort ascendending
    c2.Sort 'Sort ascending
     
    If tfAscending1 = False Then c1.Reverse 'Sort and then Reverse to sort descending
    If tfAscending2 = False Then c2.Reverse 'Sort and then Reverse to sort descending
     
    a1() = c1.Toarray()
    a2() = c2.Toarray()
     
    If tfNumbersFirst = True Then
        a() = a1()
        For i = 1 To c2.Count
            ReDim Preserve a(UBound(a) + 1)
            a(UBound(a)) = a2(i - 1)
        Next i
    Else
        a() = a2()
        For i = 1 To c1.Count
            ReDim Preserve a(UBound(a) + 1)
            a(UBound(a)) = a1(i - 1)
        Next i
    End If
     
    advArrayListSort = a()
End Function

' http://www.excelforum.com/excel-programming-vba-macros/819998-filter-and-sort-scripting-dictionary.html
'Early Binding method requires Reference: MicroSoft Scripting Runtime, scrrun.dll
Function UniqueArrayByDict(Array1d() As Variant, Optional compareMethod As Integer = 0) As Variant
  'Dim dic As Object 'Late Binding method - Requires no Reference
  'Set dic = CreateObject("Scripting.Dictionary")  'Late or Early Binding method
  Dim dic As Dictionary     'Early Binding method
  Set dic = New Dictionary  'Early Binding Method
  Dim e As Variant
  dic.CompareMode = compareMethod
  'BinaryCompare=0
  'TextCompare=1
  'DatabaseCompare=2
  For Each e In Array1d
    If Not dic.Exists(e) Then dic.Add e, Nothing
  Next e
  UniqueArrayByDict = dic.Keys
End Function

 

Obtained from the OzGrid Help Forum.

Solution provided by Kenneth Hobson.

 

See also: Index to Excel VBA Code and Index to Excel Freebies and Lesson 1 - Excel Fundamentals and Index to how to… providing a range of solutions and Index to new resources and reference sheets

 

See also:

How to create a macro for saving copy as csv with incremental file number
Macro to insert new row at bottom of table, find highest value in column A and add 1
How to create VBA to save reports, generated using macros to specific folders
How to create a macro assigned to the submit button on the "interface" sheet

 

Click here to visit our Free 24/7 Excel/VBA Help Forum where there are thousands of posts you can get information from, or you can join the Forum and post your own questions.

 

 

 

 

 


Gallery



stars (0 Reviews)