SOLVED

A simple merge function

%3CLINGO-SUB%20id%3D%22lingo-sub-2781779%22%20slang%3D%22en-US%22%3EA%20simple%20merge%20function%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2781779%22%20slang%3D%22en-US%22%3E%3CP%3EI'd%20like%20to%20write%20a%20simple%20merge%20function%20along%20these%20lines%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EFirst%2C%20find%20all%20identical%20(duplicate)%20entries%20in%20Column%20B.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThen%2C%20for%20all%20columns%20after%20column%20B%20(in%20the%20data%20range)%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EMerge%20the%20values%20in%20each%20corresponding%20cell%2C%20comma%20separated%2C%20uniquely.%20That%20is%2C%20if%20Row%20X%20and%20Y%20have%20the%20same%20value%20in%20Column%20C%2C%20keep%20only%20one%20copy.%20If%20Row%20X%20and%20Y%20have%20a%20different%20value%20in%20Column%20D%2C%20keep%20both%20in%20one%20cell%2C%20but%20separated%20by%20commas.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere's%20a%20weak%20attempt%20at%20a%20pseudocode%20for%20this%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%20For%20row%20%3D%202%20To%201000%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20For%20duplicate%20%3D%20(row%20%2B%201)%20To%201000%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20If%20Cells(duplicate%2C%202).Value%20%3D%20Cells(row%2C%202).Value%20Then%3C%2FP%3E%3CP%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20mergeDuplicate(row%2C%20duplicate)%20'%20a%20merge%20function%20(below)%20which%20takes%20in%20the%20two%20row%20indices%3C%2FP%3E%3CP%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20End%20If%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%20End%20For%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EEnd%20For%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ESub%20mergeDuplicate(row%2C%20duplicate)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%20For%20column%20%3D%203%20to%2014%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%20If%20Cells(row%2C%20column)%20!%3D%20Cells(duplicate%2C%20column)%20Then%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20Cells(row%2C%20column).Value.Append(%22%2C%20%22%20%2B%20Cells(duplicate%2C%20column).Value)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%20End%20If%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%20End%20For%3C%2FP%3E%3CP%3E%26nbsp%3B%20Delete%20Rows(duplicate)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EEnd%20Sub%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EI%20can%20imagine%20there%20are%20more%20sophisticated%20ways%20to%20do%20this%20without%20so%20much%20iteration%20(storing%20values%20or%20cell%20references%20in%20lists%2C%20defining%20certain%20functions%20and%20objects)%2C%20but%20I%20decided%20this%20was%20a%20good%2C%20simple%2C%20pure%20way%20to%20start.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECould%20any%20comment%20on%20my%20function%2C%20perhaps%20by%20providing%20a%20more%20elegant%2C%20VBA-style%20way%20of%20doing%20it%3F%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThank%20you%20very%20much.%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-LABS%20id%3D%22lingo-labs-2781779%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3EMacros%20and%20VBA%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2782857%22%20slang%3D%22en-US%22%3ERe%3A%20A%20simple%20merge%20function%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2782857%22%20slang%3D%22en-US%22%3EFirst%20I%20ask%20if%20you%20really%20want%20to%20change%20the%20data%20or%20create%20a%20'better'%20way%20to%20view%20the%20data.%20I%20ask%20because%20often%20people%20treat%20excel%20sheets%20as%20data%20collection%2C%20storage%20and%20viewing%20when%20often%20it%20is%20better%20to%20have%20data%20collection%20and%20storage%20set%20up%20separate%20from%20data%20viewing.%20For%20example%2C%20that%20is%20why%20Excel%20has%20Pivot%20Tables.%20By%20the%20way%2C%20you%20might%20consider%20if%20a%20Pivot%20Table%20view%20might%20be%20adequate%20for%20what%20you%20want.%20If%20not%2C%20some%20the%20new%20Dynamic%20Array%20formulas%20could%20be%20used%20to%20generate%20a%20view%20that%20you%20want.%3CBR%20%2F%3EThat%20all%20said%2C%20if%20you%20want%20to%20change%20the%20data%20(i.e.%20use%20VBA)%20then%20I%20might%20suggest%20a%20slight%20variation%20on%20your%20pseudo-code%3A%3CBR%20%2F%3ESub%20mergeDups()%3CBR%20%2F%3EDim%20i%2C%20FoundRow%2C%20C%2C%20LastRow%2C%20LastCol%20As%20Long%3CBR%20%2F%3EWith%20ActiveSheet%3CBR%20%2F%3ELastRow%20%3D%20.UsedRange.Rows.Count%3CBR%20%2F%3ELastCol%20%3D%20.UsedRange.Columns.Count%3CBR%20%2F%3EFor%20i%20%3D%20LastRow%20To%201%20Step%20-1%3CBR%20%2F%3EFor%20FoundRow%20%3D%201%20To%20i%3CBR%20%2F%3EIf%20(.Cells(i%2C%201)%20%3D%20.Cells(FoundRow%2C%201))%20Then%20Exit%20For%3CBR%20%2F%3ENext%20FoundRow%3CBR%20%2F%3EIf%20(FoundRow%20%26lt%3B%20i)%20Then%3CBR%20%2F%3EFor%20C%20%3D%202%20To%20LastCol%3CBR%20%2F%3EIf%20InStr(1%2C%20.Cells(FoundRow%2C%20C).Value2%2C%20.Cells(i%2C%20C).Value2)%20%3D%200%20Then%3CBR%20%2F%3E.Cells(FoundRow%2C%20C).Value2%20%3D%20.Cells(FoundRow%2C%20C).Value2%20%26amp%3B%20%22%2C%20%22%20%26amp%3B%20.Cells(i%2C%20C).Value2%3CBR%20%2F%3EEnd%20If%3CBR%20%2F%3ENext%20C%3CBR%20%2F%3E.Cells(i%2C%201).EntireRow.Delete%3CBR%20%2F%3EEnd%20If%3CBR%20%2F%3ENext%20i%3CBR%20%2F%3EEnd%20With%3CBR%20%2F%3EEnd%20Sub%3C%2FLINGO-BODY%3E
Contributor

I'd like to write a simple merge function along these lines:

 

First, find all identical (duplicate) entries in Column B.

 

Then, for all columns after column B (in the data range):

 

Merge the values in each corresponding cell, comma separated, uniquely. That is, if Row X and Y have the same value in Column C, keep only one copy. If Row X and Y have a different value in Column D, keep both in one cell, but separated by commas.

 

Here's a weak attempt at a pseudocode for this:

 

 

  For row = 2 To 1000:

 

      For duplicate = (row + 1) To 1000:

 

        If Cells(duplicate, 2).Value = Cells(row, 2).Value Then

             mergeDuplicate(row, duplicate) ' a merge function (below) which takes in the two row indices

       End If

 

 

    End For

 

 

End For

 

Sub mergeDuplicate(row, duplicate)

 

  For column = 3 to 14:

 

    If Cells(row, column) != Cells(duplicate, column) Then

 

      Cells(row, column).Value.Append(", " + Cells(duplicate, column).Value)

 

    End If

 

 

  End For

  Delete Rows(duplicate)

 

End Sub

 

I can imagine there are more sophisticated ways to do this without so much iteration (storing values or cell references in lists, defining certain functions and objects), but I decided this was a good, simple, pure way to start.

 

Could any comment on my function, perhaps by providing a more elegant, VBA-style way of doing it?

 

Thank you very much.

2 Replies
best response confirmed by jukhamil (Contributor)
Solution

First I ask if you really want to change the data or create a 'better' way to view the data. I ask because often people treat excel sheets as data collection, storage and viewing when often it is better to have data collection and storage set up separate from data viewing. For example, that is why Excel has Pivot Tables. By the way, you might consider if a Pivot Table view might be adequate for what you want. If not, some the new Dynamic Array formulas could be used to generate a view that you want.
That all said, if you want to change the data (i.e. use VBA) then I might suggest a slight variation on your pseudo-code:

Sub mergeDups()
  Dim i, FoundRow, C, LastRow, LastCol As Long
  With ActiveSheet
    LastRow = .UsedRange.Rows.Count
    LastCol = .UsedRange.Columns.Count
    For i = LastRow To 1 Step -1
      For FoundRow = 1 To i
           If (.Cells(i, 1) = .Cells(FoundRow, 1)) Then Exit For
       Next FoundRow
      If (FoundRow < i) Then
         For C = 2 To LastCol
              If InStr(1, .Cells(FoundRow, C).Value2, .Cells(i, C).Value2) = 0 Then
                     .Cells(FoundRow, C).Value2 = .Cells(FoundRow, C).Value2 & ", " & .Cells(i, C).Value2
              End If
         Next C
          .Cells(i, 1).EntireRow.Delete
       End If
    Next i
  End With
End Sub
Thanks, I'll study your response and get back to you. This is what I was hoping for, some external perspective and new ideas. Thank you very much.