Reputation: 21
I am quite new to VBA and would like to do the following but not sure how:
First, I delimit data separated by commas. (this one is fine as I can do it with the record macro option as well)
The problem is that I would also like to transpose the information from each row to a column, with the rows being one under the other. However, I would also like to add the corresponding row to the data before it was delimited. Here is an example: Example
Upvotes: 2
Views: 1682
Reputation: 2441
Google-sheets (screenshots below) here (perma-link, self-same content / functions included below in any case!). Key for labels 1 & 2:
(preface: may as well be entitled 'two-function' soln...)
STEP 1: FILTERXML as dynamic array applied to Label 1 in first instance (ref: 8 ways to split text by delimiter - J./ MacDougall Note: this is one of 2 methods that shall be considered for Step 1.
FilterXML screenshot
FilterXML function in the context of above screenshot:
=FILTERXML("<t><s>"&SUBSTITUTE(ARRAYTOTEXT(D6:D10),",","</s><s>")&"</s></t>","//s")
STEP 2. INDEX-ARRAY (map Label 1 values to corresponding Label 2 values after applying FILTERXML step)
Index-Array screenshot
Index-Array function in the context of above screenshot:
=INDEX($C$6:$C$10,MATCH("*"&D16#&"*",$D$6:$D$10,0))[5]
Viable in context of other priorities, budget, etc.
i) VB Code
Modify/adjust as you deem fit/as req.
Sub Boring_Split_Code():
ActiveCell.Formula2R1C1 = _
"=FILTERXML(""<t><s>""&SUBSTITUTE(ARRAYTOTEXT(R[-12]C:R[-8]C),"","",""</s><s>"")&""</s></t>"",""//s"")"
Range("C22").Select
'Application.CutCopyMode = False
ActiveCell.Formula2R1C1 = _
"=INDEX(R10C3:R14C3,MATCH(""*""&RC[1]#&""*"",R10C4:R14C4,0))"
End Sub
ii) VB 'mechanical-unpivot' method
Sub Unpivot()
'
' Unpivot Macro
' Creates pivot flat file source format from table with rows and columns
Dim rng As Range
Dim Ws As Worksheet
On Error Resume Next
Set rng = Application.InputBox(Prompt:="Select a range to normalize data" _
, Title:="Select a range", Default:=ActiveCell.address, Type:=8)
On Error GoTo 0
If rng Is Nothing Then
Else
Application.ScreenUpdating = False
Set Ws = Sheets.Add
i = 0
For r = 1 To rng.Rows.Count - 1
For c = 1 To rng.Columns.Count - 1
Ws.Range("A1").Offset(i, 0) = rng.Offset(0, c).Value
Ws.Range("A1").Offset(i, 1) = rng.Offset(r, 0).Value
Ws.Range("A1").Offset(i, 2) = rng.Offset(r, c).Value
i = i + 1
Next c
Next r
Ws.Range("A:C").EntireColumn.AutoFit
Application.ScreenUpdating = True
End If
End Sub
iii) Popular Mid / Match variants...
Mid-Match (Step 1, Method 2) screenshot
Mid-Match functions
In the context of recent above screenshot:
= SUBSTITUTE(ARRAYTOTEXT(D6:D10)," ","")
Primes/prepares raw data for mid/substitute/search applications...
= MID(E23,1,SEARCH(",",E23)-1)
Initiates recursive substitute method, defined as follows (data rows 2+):
= MID( SUBSTITUTE(E$23, CONCAT(E$24:E24 & "," ), "" ), 1, IFERROR( SEARCH( ",", SUBSTITUTE(E$23, CONCAT( E$24:E24 & "," ),"" ) ) - 1, LEN( $E$23 ) ) )
Upvotes: 1
Reputation: 54807
Country;Fruits
France;Apple,Oranges
Germany;Oranges,Bananas
UK;Grapes,Lemons
Sweden;Mandarines,Strawberries,Bananas, Apples
Create (OP)
=IF(A1="","",A1&";"&B1)
NotePad
.All
and Copy
(CTRL+A, CTRL+C){}
) or use CTRL+K.Use (User)
Right-click
the first cell (A1
) and Paste
(Match Destination Formatting
),Data > TextToColumns
,Next
,Delimiter
: check Semicolon
Finish
Usage/Features
Undo
.Application.Trim
will cover any redundant spaces like the one in Swedish apples.The Code
Option Explicit
Sub unpivotCommaSeparated()
Const sName As String = "Sheet1"
Const sFirst As String = "A1"
Const dName As String = "Sheet1"
Const dFirst As String = "D1"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sData As Variant
Dim rg As Range
Dim isDataInArray As Boolean
With wb.Worksheets(sName).Range(sFirst)
Debug.Print "Source First Cell: " & .Address(0, 0)
Set rg = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If Not rg Is Nothing Then
Debug.Print "Source Last Cell in First Column: " & rg.Address(0, 0)
Set rg = .Resize(rg.Row - .Row + 1, 2)
Debug.Print "Source Range: " & rg.Address(0, 0)
sData = rg.Value
isDataInArray = True
End If
End With
If isDataInArray Then
Dim srCount As Long: srCount = UBound(sData, 1)
Dim cCount As Long: cCount = UBound(sData, 2)
ReDim Preserve sData(1 To srCount, 1 To cCount + 1)
Dim drCount As Long: drCount = 1
Dim i As Long
For i = 2 To srCount
sData(i, 2) = Split(sData(i, 2), ",")
sData(i, 3) = UBound(sData(i, 2))
drCount = drCount + sData(i, 3) + 1
Next i
Dim dData As Variant: ReDim dData(1 To drCount, 1 To cCount)
Dim j As Long
For j = 1 To cCount
dData(1, j) = sData(1, j)
Next j
Dim k As Long: k = 1
For i = 2 To srCount
For j = 0 To sData(i, 3)
k = k + 1
dData(k, 1) = sData(i, 1)
dData(k, 2) = Application.Trim(sData(i, 2)(j))
Next j
Next i
With wb.Worksheets(dName).Range(dFirst).Resize(, cCount)
Debug.Print "Destination First Row Range: " & .Address(0, 0)
Set rg = .Resize(k)
Debug.Print "Destination Range: " & rg.Address(0, 0)
rg.Value = dData
Set rg = .Resize(.Worksheet.Rows.Count - .Row - k + 1).Offset(k)
Debug.Print "Clear Range: " & rg.Address(0, 0)
rg.ClearContents
End With
End If
End Sub
Upvotes: 1