-2

I have two excel worksheets ("Sheet1" and "Sheet2"). Sheet2 contains rawdata that I want to group and present in "Sheet1" based on ID. That is, I want to coerce 'FEED' and 'NUMB' based on ID, and store 'FEED' and 'NUMB' as comma separated strings (see example data below).

This procedure needs to be dynamic, i.e. if I enter new data into Sheet2, the information presented in Sheet1 is updated automatically.

Note that I'd like to do this using VBA, in which I am an absolute beginner (Microsoft Excel 2019 and non-english). I've been trying to do this in reverse (i.e. splitting data stored according to Sheet1 to Sheet2) using VBA, however I've been unsuccessfull in my trials. I generally do not prefer working in Excel although current circumstances forces my hand at this

Sheet2

| Group | ID    | FEED  | NUMB |
|:-----:|:-----:|:-----:|:----:|
| B     | B1    | C1    | 1    |
| B     | B2    | L3    | 43   |
| B     | B3    | K12   | 101  |
| B     | B1    | G1    | 86   |
| B     | B3    | H2    | 109  |
| C     | C1    | L3    | 23   |
| C     | C2    | G1    | 24   |
| C     | C1    | L4    | 54   |
| C     | C1    | K8    | 56   |

Sheet1

| Group | ID | FEED     | NUMB     |
|:-----:|:--:|:--------:|:--------:|
| B     | B1 | C1,G1    | 1,86     |
| B     | B2 | L3       | 43       |
| B     | B3 | K12,H2   | 101,109  |
| C     | C1 | L3,L4,K8 | 23,54,56 |
| C     | C2 | G1       | 24       |

dbc
  • 104,963
  • 20
  • 228
  • 340
user09034
  • 15
  • 6
  • If you are `an absolute beginner` with VBA, you might consider using the existing `=TEXTJOIN()` Function and avoid VBA entirely? See https://www.howtoexcel.org/formulas/how-to-conditionally-concatenate-a-range-formula/. –  Mar 01 '21 at 09:46
  • If this is a task and not just a learning tool for VBA, consider using Power Query (available in Windows Excel 2010+ and O365) with it's built-in `GroupBy` method. – Ron Rosenfeld Mar 01 '21 at 11:26

1 Answers1

1

Please, try the next code. It returns starting from "O1". It can return anywhere you need:

Sub TestProcessCommaSep()
 'It needs a reference to 'Microsoft Scripting Runtime'
 Dim sh As Worksheet, lastR As Long, arr, arrFin, arrInt
 Dim dict As New Scripting.Dictionary, i As Long, k As Long
 
 Set sh = ActiveSheet 'use here the sheet you need
 lastR = sh.Range("A" & sh.rows.count).End(xlUp).row
 
 arr = sh.Range("A2:D" & lastR).value   'put the range to be processed in an array
 ReDim arrFin(1 To 4, 1 To UBound(arr)) 'redim the final array to make space for maximum
 
 For i = 1 To UBound(arr) 'iterate between arr elements
    If Not dict.Exists(arr(i, 1) & "|" & arr(i, 2)) Then 'if the key does not exist:
        dict.Add arr(i, 1) & "|" & arr(i, 2), arr(i, 3) & "|" & arr(i, 4) 'it is created
    Else
        'add to the existing key the values in columns 3 and 4:
        arrInt = Split(dict((arr(i, 1) & "|" & arr(i, 2))), "|")
        dict(arr(i, 1) & "|" & arr(i, 2)) = arrInt(0) & "," & arr(i, 3) & "|" & arrInt(1) & "," & arr(i, 4)
    End If
 Next i
 'fill the final array:
 For i = 0 To dict.count - 1
    k = k + 1
    arrFin(1, k) = Split(dict.Keys(i), "|")(0)
    arrFin(2, k) = Split(dict.Keys(i), "|")(1)
    arrFin(3, k) = Split(dict.items(i), "|")(0)
    arrFin(4, k) = Split(dict.items(i), "|")(1)
 Next
 ReDim Preserve arrFin(1 To 4, 1 To k) 'keep only the elements keeping values
 'Put the header, dropping the array elements at once:
 With sh.Range("O1")
    .Resize(1, 4).value = sh.Range("A1:D1").value
    With .Offset(1).Resize(k, 4)
        .value = Application.Transpose(arrFin)
        .EntireColumn.AutoFit
    End With
 End With
End Sub

If you do not know how to add the necessary reference, please firstly run the next code, which will automatically add it. Save the workbook after that...

Sub addScrRunTimeRef()
  'Adding a reference to 'Microsoft Scripting Runtime':
  'In case of error ('Programmatic access to Visual Basic Project not trusted'):
  'Options->Trust Center->Trust Center Settings->Macro Settings->Developer Macro Settings->
  '         check "Trust access to the VBA project object model"
  Application.VBE.ActiveVBProject.References.AddFromFile "C:\Windows\SysWOW64\scrrun.dll"
End Sub
FaneDuru
  • 38,298
  • 4
  • 19
  • 27
  • Thank you. This code does exactly what I'm looking for. Note that I had to add "End Sub" at the last line of the code in order to get it to work. – user09034 Mar 01 '21 at 14:23
  • @user09034: Ups... I missed it when copied. Glad I could help. I will correct it now. – FaneDuru Mar 01 '21 at 14:28