Combine matches

liampog

Active Member
Joined
Aug 3, 2010
Messages
308
Office Version
  1. 365
  2. 2016
Platform
  1. Windows
Hi

On Sheet1, I have the following columns of data

ABCD
1DATENUMBERNAMETYPE(S)
201/01/2019123J BloggsA,B
301/01/2019456D SmithA
401/01/2019789P JonesB,C
502/01/2019123J BloggsB
602/01/2019789P JonesD
703/01/2019456D SmithA,B,C
803/01/2019789P JonesC
903/01/2019000J DoeA
1003/01/2019123J BloggsA,C
1104/01/2019456D SmithA
1205/01/2019123J BloggsA,B
1305/01/2019456D SmithB,D

<tbody>
</tbody>


On Sheet2, I have the desired output shown below.

I have already created VBA that copies the B column from Sheet1 to Sheet2 and then removes duplicates to create a unique list of numbers. I then have a VLOOKUP set up to capture the name associated with the number. My problem is Column C on Sheet2.

I want to combine all of the Types from each customer, removing any duplicate entries.

The desired output is below and you can cross-reference this to Sheet1

ABC
1NUMBERNAMETYPE(S)
2123J BloggsA,B,C
3456D SmithA,B,C,D
4789P JonesB,C,D
5000J DoeA

<tbody>
</tbody>



Is there a formula that can achieve this? I'm sure there probably is but my knowledge of Excel formulas isn't amazing.

Thanks
 

Excel Facts

Back into an answer in Excel
Use Data, What-If Analysis, Goal Seek to find the correct input cell value to reach a desired result
looks like an ideal example where using a dictionary of dictionaries would solve your problem.
 
Last edited:
Upvote 0
you can try Power Query aka Get&Transform

DATENUMBERNAMETYPE(S)NUMBERNAMETYPE
01/01/2019​
123​
J BloggsA,B123J BloggsA,B,C
01/01/2019​
456​
D SmithA456D SmithA,B,C,D
01/01/2019​
789​
P JonesB,C789P JonesB,C,D
02/01/2019​
123​
J BloggsB000J DoeA
02/01/2019​
789​
P JonesD
03/01/2019​
456​
D SmithA,B,C
03/01/2019​
789​
P JonesC
03/01/2019​
000J DoeA
03/01/2019​
123​
J BloggsA,C
04/01/2019​
456​
D SmithA
05/01/2019​
123​
J BloggsA,B
05/01/2019​
456​
D SmithB,D

Code:
[SIZE=1]// Table1
let
    Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
    Type = Table.TransformColumnTypes(Source,{{"DATE", type datetime}, {"NUMBER", type text}, {"NAME", type text}, {"TYPE(S)", type text}}),
    ROC = Table.SelectColumns(Type,{"NUMBER", "NAME", "TYPE(S)"}),
    Split = Table.ExpandListColumn(Table.TransformColumns(ROC, {{"TYPE(S)", Splitter.SplitTextByDelimiter(",", QuoteStyle.Csv), let itemType = (type nullable text) meta [Serialized.Text = true] in type {itemType}}}), "TYPE(S)"),
    Group = Table.Group(Split, {"NUMBER", "NAME"}, {{"Count", each _, type table}}),
    List = Table.AddColumn(Group, "TYPE", each List.Distinct(Table.Column([Count],"TYPE(S)"))),
    Extract = Table.TransformColumns(List, {"TYPE", each Text.Combine(List.Transform(_, Text.From), ","), type text})
in
    Extract[/SIZE]
 
Upvote 0
How about
Rich (BB code):
Sub liampog()
   Dim Cl As Range
   Dim Dic As Object
   Dim Ky As Variant
   Dim i As Long
   
   Set Dic = CreateObject("scripting.dictionary")
   For Each Cl In Range("B2", Range("B" & Rows.Count).End(xlUp))
      If Not Dic.Exists(Cl.Value) Then
         Dic.Add Cl.Value, Array(Cl.Offset(, 1).Value, CreateObject("system.collections.arraylist"))
      End If
      Ky = Split(Cl.Offset(, 2).Value, ",")
      For i = 0 To UBound(Ky)
         With Dic(Cl.Value)(1)
            If Not .contains(CStr(Ky(i))) Then .Add CStr(Ky(i))
         End With
      Next i
   Next Cl
   i = 1
   For Each Ky In Dic.Keys
      i = i + 1
      Sheets("sheet2").Range("A" & i).Resize(, 3).Value = Array(Ky, Dic(Ky)(0), Join(Dic(Ky)(1).toarray, ","))
   Next Ky
End Sub
 
Last edited:
Upvote 0
Hi

I've just realised I asked this question before. Sorry!

Thanks for your answers. I'll have a look at them. The last answer looks interesting. I assume this is a "Dictionary of Dictionaries" mentioned in the first answer, which I've never heard of before!

Thanks
Liam
 
Upvote 0
I assume this is a "Dictionary of Dictionaries" mentioned in the first answer,
No it's not, but similar
Although I forgot a bit, use
Rich (BB code):
Sub liampog()
   Dim Cl As Range
   Dim Dic As Object
   Dim Ky As Variant
   Dim i As Long
   
   Set Dic = CreateObject("scripting.dictionary")
   For Each Cl In Range("B2", Range("B" & Rows.Count).End(xlUp))
      If Not Dic.Exists(Cl.Value) Then
         Dic.Add Cl.Value, Array(Cl.Offset(, 1).Value, CreateObject("system.collections.arraylist"))
      End If
      Ky = Split(Cl.Offset(, 2).Value, ",")
      For i = 0 To UBound(Ky)
         With Dic(Cl.Value)(1)
            If Not .contains(CStr(Ky(i))) Then .Add CStr(Ky(i))
         End With
      Next i
   Next Cl
   i = 1
   For Each Ky In Dic.Keys
      i = i + 1
      Dic(Ky)(1).Sort
      Sheets("sheet2").Range("A" & i).Resize(, 3).Value = Array(Ky, Dic(Ky)(0), Join(Dic(Ky)(1).toarray, ","))
   Next Ky
End Sub
 
Upvote 0
From my OP:

Is there a formula that can achieve this?


Whilst this VBA code works perfectly, what I really wanted is some kind of lookup formula that achieves the same thing so that if the data in the Type column is changed on Sheet1, it reflects in the output automatically on Sheet2 without the need for any VBA code firing.

If there is no formula, or combination of formulas, that achieves the desired outcome, the VBA code you've detailed will be a workaround that I can put in perhaps run if with a Worksheet_Change event on any cells in the Type column on Sheet1.

Thanks for your help,
Liam

 
Last edited:
Upvote 0
I also forgot to say that I only need formulas and/or VBA code to help me with Column C on Sheet2 (the Types column). The number and name columns are already sorted.

Just a way to lookup and combine unique values from Types.

Thanks in advance,
Liam
 
Upvote 0
Formulae are not my strong point, so not sure if it can be done that way, but if it is possible it would probably be a very complex formula.
However you could use this UDF
Code:
Function liampog(Rng As Range, Crit As String) As String
   Dim Cl As Range
   Dim Lst As Object
   Dim Sp As Variant
   Dim i As Long
   
   Set Lst = CreateObject("system.collections.arraylist")
   For Each Cl In Rng
      If Cl.Value = Crit Then
         Sp = Split(Cl.Offset(, 2), ",")
         For i = 0 To UBound(Sp)
            If Not Lst.contains(CStr(Sp(i))) Then Lst.Add CStr(Sp(i))
         Next i
      End If
   Next Cl
   Lst.Sort
   liampog = Join(Lst.toarray, ",")
End Function
Used like
=liampog(Sheet1!$B$2:$B$13,A1)
 
Upvote 0
Hi Fluff

Thanks for the reply.

Whilst this works perfectly, it processes extremely slowly, to the point where Excel goes into Not Responding mode until it's finished, and this is just for ONE formula.

The next part of my VBA code will be autofilling this formula down as far as there is data in the first column. This could potentially be several hundred rows of data.

Do you have any other suggestions? Or should it be taking this long?

Thanks
Liam
 
Upvote 0

Forum statistics

Threads
1,214,867
Messages
6,122,002
Members
449,059
Latest member
mtsheetz

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