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 |
Solution:
Run this with that sheet active.
'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.