Reputation: 21
I have a large data set consisting of two columns with repeat row names but unique row values. Here is a small example:
A 1
A 2
A 3
A 4
A 5
A 6
A 7
B 8
B 9
B 10
B 11
B 12
B 13
B 14
C 15
C 16
C 17
C 18
C 19
C 20
C 21
I would like to convert this to a few rows with multiple columns. Like this:
A 1 2 3 4 5 6 7
B 8 9 10 11 12 13 14
C 15 16 17 18 19 20 21
I tried to record a macro, but I could not figure out how to get the macro to not only select the range of cells from B1:B7 but also from B8:B14 when I click on B8. The macro always reverted to B1:7.
Here is my example macro:
Sub Macro2()
Range("B1:B7").Select
Selection.Copy
Range("D2").Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
End Sub
I have done some extensive googling and could not come up with an easy answer. I apologize if this is rudimentary.
Thank you for your help.
I should have been more specific with how my data looks. Here is an example, but I have many more rows for each row name.
A*01:01 24575.73
A*01:01 66.87
A*01:01 38.21
A*01:01 24532.88
A*01:01 2090.44
A*01:01 61.87
A*01:01 41.01
A*02:01 306.68
A*02:01 24.96
A*02:01 23182.25
A*02:01 28.23
A*02:01 54.94
A*02:01 39.87
A*02:01 22734.92
A*02:03 22.83
A*02:03 131.63
A*02:03 35.51
A*02:03 71.33
A*02:03 30.82
A*02:03 24.21
A*02:03 25.23
Upvotes: 2
Views: 4078
Reputation: 55672
This method uses a variant array to quickly perform the transposing
It works on
X = Range([a1], Cells(Rows.Count, "B").End(xlUp))
C1
with this line [c1].Resize(UBound(X, 1), UBound(X, 1)) = Y
code
Sub ByeSwanny()
Dim X
Dim Y
Dim lngRow As Long
Dim lngCnt1 As Long
Dim lngCnt2 As Long
X = Range([a1], Cells(Rows.Count, "B").End(xlUp))
ReDim Y(1 To UBound(X, 1), 1 To UBound(X, 1))
Y(1, 1) = X(1, 1)
Y(1, 2) = X(1, 2)
lngCnt1 = 2
lngCnt2 = 1
For lngRow = 2 To UBound(X, 1)
If X(lngRow, 1) = X(lngRow - 1, 1) Then
lngCnt1 = lngCnt1 + 1
Y(lngCnt2, lngCnt1) = X(lngRow, 2)
Else
lngCnt1 = 2
lngCnt2 = lngCnt2 + 1
Y(lngCnt2, 1) = X(lngRow, 1)
Y(lngCnt2, 2) = X(lngRow, 2)
End If
Next lngRow
[c1].Resize(UBound(X, 1), UBound(X, 1)) = Y
End Sub
Upvotes: 1
Reputation: 29308
A Simple Solution would be:
Sub transposer()
Dim lcell As Range
Dim c_row As Integer
Dim a_cell As String
Dim c_col As Long
Sheet1.Columns("A:B").Sort key1:=Sheet1.Range("A2"), order1:=xlAscending, Header:=xlYes
For Each lcell In Sheet1.Range("$A$1", "$A$" & Sheet1.Cells(Rows.Count, 1).End(xlUp).Row)
If a_cell <> lcell Then
c_row = c_row + 1
a_cell = lcell
Sheet1.Cells(c_row, 3) = a_cell
c_col = 4
End If
Sheet1.Cells(c_row, c_col) = Sheet1.Cells(lcell.Row, 2)
c_col = c_col + 1
Next lcell
Sheet1.Range("A:B").EntireColumn.Delete
End Sub
This assumes there are headers if no headers then
Sheet1.Columns("A:B").Sort key1:=Sheet1.Range("A2"), order1:=xlAscending, Header:=xlYes
Should be
Sheet1.Columns("A:B").Sort key1:=Sheet1.Range("A1"), order1:=xlAscending
Upvotes: 1
Reputation: 15551
The solution for this is slightly adapted from here (see also this accepted answer). If your source range is A1:B21 (it can be easily extended), and you want your new data to be stored in D1:L3, use the following formulas:
For D1: =INDEX($A$1:$A$50,ROW()*7-6,1)
For E1: =INDEX($B$1:$B$50,ROW()*7-6,1)
For F1: =INDEX($B$1:$B$50,ROW()*7-5,1)
For G1: =INDEX($B$1:$B$50,ROW()*7-4,1)
... and so on for row 1. Then copy from D1:L1 downwards as needed.
The upside of this approach is that it does not use VBA.
The downside is that it uses a fixed number of items for each letter. If that were variable, I conceive that more complex formulas might do the job, and there is a clear way of doing it with VBA.
Upvotes: 0
Reputation: 4513
Try somethign like this:
Const DEST_COLUMN As Integer = 5
Sub ByMakah()
Dim lastRow As Integer, rowIndex As Integer
Dim name As String, value As String, destionationRow As Integer, destionationCol As Integer
'Clear Area
Range("E:AA").ClearContents
lastRow = Range("A10000").End(xlUp).Row
Range(Cells(1, 1), Cells(lastRow, 1)).Copy
Cells(1, DEST_COLUMN).PasteSpecial
Range(Cells(1, DEST_COLUMN), Cells(lastRow, DEST_COLUMN)).RemoveDuplicates Columns:=1, Header:=xlYes
'Fill values
For rowIndex = 2 To lastRow
name = Cells(rowIndex, 1)
value = Cells(rowIndex, 2)
destionationRow = WorksheetFunction.Match(name, Columns(DEST_COLUMN), False)
'Get lastCol
destionationCol = Cells(destionationRow, 1000).End(xlToLeft).Column + 1
Cells(destionationRow, destionationCol) = value
Next rowIndex
End Sub
Upvotes: 1