Home > OS >  How to extract the unique values from a separate ranges and concatenate to the adjacent column (offs
How to extract the unique values from a separate ranges and concatenate to the adjacent column (offs

Time:07-30

I need to extract the unique values from a separate ranges and concatenate to the adjacent column (offset (,-1) on the same range.
As you see on the below picture, I sort my dataset by column_A ,so all duplicate values on column_A will be together.
I need to put the duplicate values on column_A with the respective cells on the same rows into a variable Range e.g rng1 = [A2:C4],
Then extract unique values found on rng1.columns(3) and concatenate to each cell on rng1.columns(2) ,range(“B2:B4”)
By the same rng2 will be = [A5:C7] and so on.
The problem is I do know how when ID values is duplicates to put them and it’s adjacent cells on the same rows into a variable range and process it !
At end column C will be be deleted.
In advance, great thanks for your learning support. enter image description here

Sub Extract_unique_values_and_combine_in_adjacent_cells()
 
   Dim ws As Worksheet: Set ws = ActiveSheet
    Dim rng As Range
     Set rng = ws.Range("A2:C" & ws.Cells(Rows.Count, "A").End(xlUp).Row)
 
   Dim arr: arr = rng.Value2
    Dim i As Long
     For i = LBound(arr) To UBound(arr)
 
   On Error Resume Next 'skip error if i= 1
      If arr(i, 1) = arr(i   1, 1) Or _
         arr(i, 1) = arr(i - 1, 1) Then
        arr(i, 2) = arr(i, 2) & vbLf & unique(ws.Range("C2:C4").Value2) 'I need (crg) to be dynamic
      End If
   On Error GoTo 0
 
    Next i
 
   rng.Value = arr
 
End Sub
 
Function unique(crg)
 
   Dim cel, a
     With CreateObject("scripting.dictionary")
       For Each cel In crg
         a = .Item(cel)
       Next
     unique = Join(.Keys, vbLf)
    End With
 
End Function

CodePudding user response:

Please, try the next code. It uses a dictionary and arrays to keep, process and return the necessary strings. It will process all categories (unique in A:A) being in any order:

Sub CombineRanges()
   Dim sh As Worksheet, lastR As Long, arr, arrDict, dict As Object
   Dim arrDB, arrDC, mtch, arrFin, i As Long, j As Long, k As Long
   
   Set sh = ActiveSheet
   lastR = sh.Range("A" & sh.rows.count).End(xlUp).row
   
   arr = sh.Range("A2:C" & lastR).Value2
   Set dict = CreateObject("Scripting.Dictionary")
   
   For i = 1 To UBound(arr)
        If Not dict.Exists(arr(i, 1)) Then
            dict.Add arr(i, 1), Array(arr(i, 2), arr(i, 3)) 'place the strings from columns B and C
        Else
            arrDict = dict(arr(i, 1))                       'extract the array from dict items (it cnnot be modified inside the item)
            arrDict(0) = arrDict(0) & "|" & arr(i, 2)       'place in the array first element the strings collected from B:B
            arrDC = Split(arrDict(1), vbLf)                 'try splitting the second array element (string(s) from C:C)
            If UBound(arrDC) = 0 Then                       'if only one element:
                If arrDC(0) <> arr(i, 3) Then arrDict(1) = arrDict(1) & vbLf & arr(i, 3) 'add to it the value from C:C, separated by vbLf
            Else
                mtch = Application.match(arr(i, 3), arrDC, 0) 'check unicity of the string from C:C
                If IsError(mtch) Then                         'only if not existing:
                    arrDict(1) = arrDict(1) & vbLf & arr(i, 3)'add it to the string to be used in the next step
                End If
            End If
            dict(arr(i, 1)) = arrDict                         'put back the array in the dictionary item
        End If
   Next i

   ReDim arrFin(1 To UBound(arr), 1 To 2): k = 1              'redim the final array and initialize k (used to fill the array)
   For i = 0 To dict.count - 1                                'iterate between the dictionary keys/items:
        arrDict = dict.Items()(i)                             'place the item array in an array
        arrDB = Split(arrDict(0), "|")                        'obtain an array of B:B strins from the item first array element
        For j = 0 To UBound(arrDB)   'how many unique keys exists!
                arrFin(k, 1) = dict.Keys()(i)                 'place the dictionry key per each iteration
                arrFin(k, 2) = arrDB(j) & vbLf & arrDict(1)   'build the string of the second column
                k = k   1
        Next j
   Next i
   'drop the processed result near the existing range (for easy visual comparison):
   sh.Range("D2").Resize(UBound(arrFin), 2).Value2 = arrFin
End Sub

The above code assumes what I wrote in my comment placed some time before and you din not confirm/infirm...

Edited:

Please, test the next version. It will return only a column keeping the concatenated B:C columns value and skips the empty values in C:C, if the case. It will return in D:D, too. After testing, if it does what you need, just change "D" with "B" in the last code line:

Sub CombineRangesOneColumn()
   Dim sh As Worksheet, lastR As Long, arr, arrDict, dict As Object
   Dim arrDB, arrDC, mtch, arrFin, i As Long, j As Long, k As Long
   
   Set sh = ActiveSheet
   lastR = sh.Range("A" & sh.rows.count).End(xlUp).row
   
   arr = sh.Range("A2:C" & lastR).Value2
   Set dict = CreateObject("Scripting.Dictionary")
   
   For i = 1 To UBound(arr)
        If Not dict.Exists(arr(i, 1)) Then
            dict.Add arr(i, 1), Array(arr(i, 2), arr(i, 3)) 'place the strings from columns B and C
        Else
            arrDict = dict(arr(i, 1))                                   'extract the array from dict items (it cnnot be modified inside the item)
            arrDict(0) = arrDict(0) & "|" & arr(i, 2)        'place in the array first element the strings collected from B:B
            arrDC = Split(arrDict(1), vbLf)                      'try splitting the second array element (string(s) from C:C)
            If UBound(arrDC) = 0 Then                           'if only one element:
                If arrDC(0) <> arr(i, 3) Then arrDict(1) = arrDict(1) & IIf(arr(i, 3) = "", "", vbLf & arr(i, 3)) 'add to it the value from C:C, separated by vbLf
            Else
                mtch = Application.match(arr(i, 3), arrDC, 0) 'check unicity of the string from C:C
                If IsError(mtch) Then                                          'only if not existing:
                    arrDict(1) = arrDict(1) & IIf(arr(i, 3) = "", "", vbLf & arr(i, 3))       'add it to the string to be used in the next step
                End If
            End If
            dict(arr(i, 1)) = arrDict                                             'put back the array in the dictionary item
        End If
   Next i

   ReDim arrFin(1 To UBound(arr), 1 To 1): k = 1            'redim the final array and initialize k (used to fill the array)
   For i = 0 To dict.count - 1                                                'iterate between the dictionary keys/items:
        arrDict = dict.Items()(i)                                               'place the item array in an array
        arrDB = Split(arrDict(0), "|")                                      'obtain an array of B:B strins from the item first array element
        For j = 0 To UBound(arrDB)   'how many unique keys exists!                     'place the dictionry key per each iteration
                arrFin(k, 1) = arrDB(j) & vbLf & arrDict(1)       'build the string of the second column
                k = k   1
        Next j
   Next i
   'drop the processed result near the existing range (for easy visual comparison):
   sh.Range("D2").Resize(UBound(arrFin), 1).Value2 = arrFin
End Sub
  • Related