VBA transform rows to column - vba

I have a worksheet in excel which looks like this
name variant1 value1 variant2 value2
----- -------- ------ -------- ------
name1 variantA1 valueA1 variantB1 valueB1
name2 variantC2 valueC2 variantD2 valueD2
And I want to transform it to such a structure:
name variant value
---- -------- ------
name1
variantA1 valueA1
variantB1 valueB2
name2
variantC2 valueC2
variantD2 valueD2
I will use this macro quite often, it may happen that there will be 10 different variants for each name and I don't know how many rows will be in the worksheet.
I've written VBA macro and I'm not sure why it doesn't work:
Sub import_format()
Dim ws As Worksheet
Dim LastRow As Long, i As Long
Dim NumberOfVariants As Long
Dim j As Long
Dim ColumnIndex As Long
Set ws = Sheets("Sheet1") '~~> Name of the sheet which has the list
LastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
NumberOfVariants = 2
ColumnIndex = 2 '<~~ index of the first variant
For i = 2 To LastRow '<~~ Set 2 if row 1 has headers
i = i + 1
ws.Rows(i & ":" & i + NumberOfVariants).Insert shift:=xlDown
i = i - 1
For j = 0 To (NumberOfVariants * 2) - 1
ws.Range(Cells(ColumnIndex + (j * 2), i), Cells(ColumnIndex + (j * 2) + 1, i)).Select
Selection.Cut
ws.Range(Cells(ColumnIndex + (j * 2), i + j + 1), Cells(ColumnIndex + (j * 2) + 1, i + j + 1)).Paste
Next j
Next i
End Sub
The way I tried to to this was to insert rows = number of variants and cut and paste proper values.
I will be grateful for all the hints! ;-)

Try this one :)
Option Explicit
Sub import_format()
Dim ws As Worksheet
Dim i, j, LastRow, ColumnIndex, NumberOfVariants As Integer
Set ws = Sheets("Sheet1") '~~> Name of the sheet which has the list
LastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
NumberOfVariants = 4
ColumnIndex = 2 '<~~ index of the first variant
For i = 2 To LastRow + (LastRow - 2) * (NumberOfVariants - 1) Step NumberOfVariants '<~~ Set 2 if row 1 has headers; Actual last row = current last row + lines which will be inserted
ws.Rows(i + 1 & ":" & i + NumberOfVariants - 1).Insert shift:=xlDown 'Insert rows based on number of variants
For j = 2 To (NumberOfVariants - 1) * 2 Step 2 'Walking through the variants, starting in column 2, variant + value are 2 columns, therefore using step 2
ws.Range(Cells(i, ColumnIndex + j), Cells(i, ColumnIndex + j + 1)).Cut _
Destination:=ws.Range(Cells(i + j / 2, ColumnIndex), Cells(i + j / 2, ColumnIndex + 1))
Next j
Next i
End Sub

Related

Count rows and columns in ranges of varying size

The following short program should cycle through all sheets within a workbook and compare the values in the cells from (C11:end) to the cell in column B for that row, and then repeat this for each row below it where there is data.
The code won't run due to an 'overflow' error, implying that the variable NumRows is too large for the integer type (I think?). However, whilst the NumRows and NumCols vary from sheet to sheet, there are always <100 in each case. Changing the type to 'Long' causes Excel to hang. I'm not sure why this is happening, C11 is always bounded on both its right and bottom side by data so the .End function shouldn't be generating massive numbers.
I'm very new to all this so if anyone could please explain or suggest edits I'd be very grateful.
Sub cond_format()
Application.ScreenUpdating = False
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Activate
Dim i As Integer
Dim j As Integer
Dim NumRows As Integer
Dim NumCols As Integer
NumRows = ws.Range("C11", ws.Range("C11").End(xlDown)).Rows.Count
NumCols = ws.Range("C11", ws.Range("C11").End(xlToRight)).Columns.Count
For i = 1 To NumRows
For j = 1 To NumCols
If Cells(10 + i, 2 + j).Value >= (Cells(i + 10, 2).Value) * 1.2 Then
Cells(10 + i, 2 + j).Interior.Color = 10092492
ElseIf Cells(10 + i, 2 + j).Value <= (Cells(i + 10, 2).Value) * 0.8 Then
Cells(10 + i, 2 + j).Interior.Color = 5263615
End If
Next
Next
Next ws
End Sub

Copy Rows into columns using VBA

I have a very little experience with VBA, and I would really appreciate any help with this issue.
I need to convert rows into columns from sheet 1 to sheet 2.
Input File
Desired Output
Sample data
My Code
Sub TransposeSpecial()
Dim lMaxRows As Long 'max rows in the sheet
Dim lThisRow As Long 'row being processed
Dim iMaxCol As Integer 'max used column in the row being processed
lMaxRows = Cells(Rows.Count, "A").End(xlUp).Row
lThisRow = 2 'start from row 2
Do While lThisRow <= lMaxRows
iMaxCol = Cells(lThisRow, Columns.Count).End(xlToLeft).Column
If (iMaxCol > 1) Then
Rows(lThisRow + 1 & ":" & lThisRow + iMaxCol - 1).Insert
Range(Cells(lThisRow, 2), Cells(lThisRow, iMaxCol)).Copy
Range("C" & lThisRow + 1).Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=False, Transpose:=True
Range(Cells(lThisRow, 2), Cells(lThisRow, iMaxCol)).Clear
lThisRow = lThisRow + iMaxCol - 1
lMaxRows = Cells(Rows.Count, "A").End(xlUp).Row
End If
lThisRow = lThisRow + 1
Loop
End Sub
Output obtained by Code
Desired output
Here you go, I made this flexible code. Just update the variables in the beginning.
Sub Transpose_my_cells()
Dim rng As Range
Dim sheet1, sheet2, addr As String
Dim src_top_row, src_left_col, dst_top_row, dst_left_col, data_cols, y As Integer
Application.ScreenUpdating = False
sheet1 = "Sheet1" 'Put your source sheet name here
sheet2 = "Sheet2" 'Put your destiny sheet name here
src_top_row = 1 'Put the top row number of the source here
src_left_col = 1 'Put the left col number of the source here
dst_top_row = 1 'Put the top row number of the destiny here
dst_left_col = 1 'Put the left col number of the destiny here
'Count data columns
data_cols = 0
Do Until Worksheets(sheet1).Cells(src_top_row, src_left_col + data_cols + 1) = ""
data_cols = data_cols + 1
Loop
'start copying data
With Worksheets(sheet1)
'first header
.Cells(src_top_row, src_left_col).Copy
addr = Cells(dst_top_row, dst_left_col).Address
Worksheets(sheet2).Range(addr).PasteSpecial
y = 0
'loop for each source row
Do Until .Cells(src_top_row + y + 1, src_left_col) = ""
'Create First column repetitions
.Cells(src_top_row + y + 1, src_left_col).Copy
addr = Cells(dst_top_row + y * data_cols + 1, dst_left_col).Address & ":" & Cells(dst_top_row + y * data_cols + data_cols, dst_left_col).Address
Worksheets(sheet2).Range(addr).PasteSpecial
'Transpose Data Headers
addr = Cells(src_top_row, src_left_col + 1).Address & ":" & Cells(src_top_row, src_left_col + data_cols).Address
.Range(addr).Copy
Worksheets(sheet2).Cells(dst_top_row + y * data_cols + 1, dst_left_col + 1).PasteSpecial Transpose:=True
'Transpose Data columns
Set rng = Cells(src_top_row + y + 1, src_left_col + 1)
addr = rng.Address & ":" & rng.Offset(0, data_cols - 1).Address
.Range(addr).Copy
Worksheets(sheet2).Cells(dst_top_row + y * data_cols + 1, dst_left_col + 2).PasteSpecial Transpose:=True
y = y + 1
Loop
End With
Application.ScreenUpdating = True
End Sub
Using VBA:
Sub Transpose_my_cells()
Worksheets("Sheet1").Range("A1:E1").Copy
Worksheets("Sheet2").Range("A1").PasteSpecial Transpose:=True
End Sub
Notes:
Change Sheet1 and Sheet2 with your sheet names as shown in the VBA sheet list.
change A1:E1 to the source cell range
change A1 to the destiny top cell
There is probably a much easier/cleaner way to do this but it works. The way it's written now, it will take the data in Sheet1 and output the transposed data on Sheet2. It should work as long as your data starts in cell A1.
Option Explicit
Sub transpose()
Dim names() As String
Dim count As Long
Dim i As Long
Dim j As Long
Dim rng As Range
Dim tmp As Long
Sheets("Sheet1").Activate
count = 0
With ThisWorkbook.Sheets("Sheet1")
Do Until .Cells(1, 2 + count) = ""
count = count + 1
Loop
ReDim names(0 To count - 1)
count = 0
Do Until .Cells(1, 2 + count) = ""
names(count) = .Cells(1, 2 + count).Value
count = count + 1
Loop
.Range("A2").Activate
Set rng = Range(Selection, Selection.End(xlDown))
End With
j = 0
With ThisWorkbook.Sheets("Sheet2")
.Cells(1, 1).Value = "ID"
.Cells(1, 2).Value = "Name"
.Cells(1, 3).Value = "Value"
For i = 0 To rng.count * count - 1
If i Mod count = 0 Then
j = j + 1
Range(Cells(j + 1, 2), Cells(j + 1, count + 1)).Copy
.Cells(i + 2, 3).PasteSpecial transpose:=True
End If
.Cells(i + 2, 1).Value = rng(j).Value
.Cells(i + 2, 2).Value = names(i Mod count)
Next i
.Activate
End With
End Sub

Loop for deciding first and last row of different entry in column A

I'm looking for a loop code which provides me with the first and last row of an 'Name' in column A.
A
1 Phill
2 Phill
3 Phill
4 Phill
5 Phill
6 Phill
7 Matthew
8 Matthew
9 Matthew
10 Matthew
11 Hendry
12 Hendry
13 Hendry
etc. etc.
The results should be something like this on other sheet:
A B C
1 Name Start_Row End_Row
2 Phill 1 6
3 Matthew 7 10
4 Hendry 11 13
5 etc. etc. etc.
I experimented with different loops but can't seem to get the good loop code which gets me started.
This is what I have:
If wsData.Cells(i + DOF, 1) <> curName Then
wbMain.Activate
For i = 1 To LastRow
curName = wsData.Cells(i + DOF, 1).Value
NameCount = NameCount + 1
wbWellsTable.Sheets("Sheet1").Cells(NameCount + 1, 1) = wbMain.Sheets("Data").Rows(i + DOF)
Start_Row = wsData.Cells(i + DOF, 1).Value
Counter = Counter + 1
wbWellsTable.Sheets("Sheet1").Cells(Counter + 1, 2) = wbMain.Sheets("Data").Rows(i + DOF)
End_Row = wsData.Cells(i + DOF, 1).Value
Bounter = Bounter + 1
wbWellsTable.Sheets("Sheet1").Cells(Bounter + 1, 3) = wbMain.Sheets("Data").Rows(i + DOF)
Next i
End If
Hope you guys can help me!
I'm not going to write the whole code for the output etc, but here's a good general function to return the first & last rows for you:
Function FindRow(sht As Worksheet, Col As String, str As String, Direction As Long) As Long
FindRow = sht.Columns(Col).Cells.Find(str, SearchOrder:=xlByRows, LookIn:=xlFormulas, SearchDirection:=Direction).Row
End Function
You can call it in your regular sub/function like this:
Dim FirstRow As Long, LastRow As Long
FirstRow = FindRow(sht:=YourWorkSheetObject, Col:="A", str:="Text To Find", Direction:=xlNext)
LastRow = FindRow(sht:=YourWorkSheetObject, Col:="A", str:="Text To Find", Direction:=xlPrevious)
Depending on the direction, it simply returns the row number of the first or last row in the specified column which matches the text you want. With these values you should be able to factor them into the rest of your code.
Without VBA, place the names in column B. In C1 enter:
=MATCH(B1,A:A,0)
and copy down and in D1 enter:
=LOOKUP(2,1/(A:A=B1),ROW(A:A))
and copy down:
With VBA:
Option Explicit
Sub rowfinder()
Dim ws As Worksheet
Dim rng As Range
Dim cell As Range
Dim currentName As String
Dim currentMin As Integer
Dim startRow As Integer
Dim startColumn As Integer
Dim outputColumn As Integer
Dim outputRow As Integer
Set ws = ThisWorkbook.Worksheets(1)
startRow = 2
startColumn = 1
outputColumn = 2
outputRow = 2
ws.Cells(startRow + 1, startColumn).End(xlDown).Select
Set rng = ws.Range(ws.Cells(startRow + 1, startColumn), ws.Cells(startRow + 1, startColumn).End(xlDown))
currentName = ws.Cells(startRow, startColumn).Value
currentMin = Cells(startRow, startColumn).Row
ws.Cells(outputRow, outputColumn).Value = currentName
ws.Cells(outputRow, outputColumn + 1).Value = currentMin
For Each cell In rng
If cell.Value <> currentName Then
ws.Cells(outputRow, outputColumn + 2).Value = cell.Row - 1
currentName = cell.Value
currentMin = cell.Row
outputRow = outputRow + 1
ws.Cells(outputRow, outputColumn).Value = currentName
ws.Cells(outputRow, outputColumn + 1).Value = currentMin
End If
Next cell
Set cell = rng.End(xlDown)
ws.Cells(outputRow, outputColumn + 2).Value = cell.Row
End Sub
Using your worksheet names
Dim wsData as Worksheet
Dim wsMain as Worksheet
Set wsData = wbMain.Sheets("Data")
Set wsMain = wwbWellsTable.Sheets("Sheet1")
' Get first value
i = 1
lastName = wsData.Cells(i, 1).Value
i = i + 1
curName = wsData.Cells(i, 1).Value
startRow = i
NameCount = 1
Do until curName = ""
if curName <> lastName then
With wksMain
NameCount = NameCount + 1 ' increment row to skip first header line
.Cells(NameCount, 1) = lastName
.Cells(NameCount, 2) = startRow
.Cells(NameCount, 3) = i - 1 ' last Row
End With
lastName = curName
startRow = i
endif
i = i + 1
curName = wsData.Cells(i, 1).Value
Loop
' Write out lst record
With wksMain
NameCount = NameCount + 1
.Cells(NameCount, 1) = lastName
.Cells(NameCount, 2) = startRow
.Cells(NameCount, 3) = i - 1 ' last Row
End With

Looping through dynamic columns and rows and transposing data

I have a dataset that is dynamic, meaning N number of rows and N number of columns (groups). The first screenshot is how the data looks with 3 groups, but as I said it could be N number of groups. There can also be N number of items.
Initial Data:
The second screenshot shows how the data should look. I need to write the item name for every score (numeric value in that row). So I have to transpose the data somehow. I need to loop through the columns, but don't know how divide the groups in the loop since they have the same column headers. Only the definition and group number are always unique.
This has to be done in VBA.
Final data after looping through rows and columns and "transposing":
Thanks
EDIT: Here's the code I've tried so far, which leaves spaces between the sets and only works for the first group.
Sub transposeData()
Dim ws As Worksheet
Dim ws2 As Worksheet
Dim lastRow As Long
Dim i As Long
Dim lastCol As Long
Dim j As Long
Dim n As Integer
Dim y As Long
Dim tempVal As Integer
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set ws2 = Workbooks("Workbook2").Worksheets("Sheet1")
lastRow = ws.Cells(ws.Rows.Count, 2).End(xlUp).Row
lastCol = ws.Cells(ws2.Rows.Count, 1).End(xlUp).Row
For i = 3 To lastRow Step 1
For y = 3 To lastRow Step 1
For j = 3 To lastCol Step 1
If ws.Cells(i, j) <> vbNullString Then
tempVal = ws.Cells(i, j).Value
ws2.Cells(y, 2) = ws.Cells(i, 2).Value
ws2.Cells(y, 3) = tempVal
ws2.Cells(y, "K") = ws.Cells(2, j).Value
End If
If tempVal <> 0 And tempVal - 1 Then
y = y + 1
End If
If j = 41 Then
i = i + 1
End If
tempVal = 0
y = y
Next j
Next y
Next i
End Sub
I took advantage of Excel's Transpose ability to get this code to work based on your sample data exactly as it is shown:
Sub Transpose()
Dim ws As Worksheet
Set ws1 = ThisWorkbook.Worksheets("Sheet1") 'Sheets("Sheet1")
Set ws2 = Workbooks("Workbook2").Worksheets("Sheet1") 'Sheets("Sheet2")
ws2.Range("A1:D1").Value = Array("Name", "Value", "Test", "Defintion")
With ws1
'how many groups are there so we know how many times to transpose
'we find this out by counting the number of times "Defintion" appears
Dim lDef As Long
lDef = Application.WorksheetFunction.CountIf(.Rows(2), "Definition")
'get last row where grouped data appears
Dim lRow As Long
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
Dim l As Long
For l = 3 To lRow 'loop through items
Dim rDef As Range, sFirst As String
Set rDef = .Rows(2).Find("Definition") 'find first instance of "Definition"
sFirst = rDef.Address 'get address of first occurence so we can test if we reached it again
'list Name (aka Item) (for as many rows as needed defined by how many groups * 4 (1 for each test))
With ws2
.Range("A" & .Rows.Count).End(xlUp).Offset(1).Resize(4 * lDef).Value = ws1.Range("A" & l)
End With
Do
'transpose values
rDef.Offset(l - 2, 1).Resize(1, 4).Copy 'uses l-2 to offset for each row throughout the loop
With ws2
'paste values (test results)
.Range("B" & .Rows.Count).End(xlUp).Offset(1).Resize(4, 1).PasteSpecial xlPasteValues, Transpose:=True
'load test cases
.Range("C" & .Rows.Count).End(xlUp).Offset(1).Resize(4, 1).Value = Application.WorksheetFunction.Transpose(Array("A", "B", "C", "D"))
'load definitions
.Range("D" & .Rows.Count).End(xlUp).Offset(1).Resize(4, 1).Value = Application.WorksheetFunction.Transpose(rDef.Offset(1).Value)
End With
Set rDef = .Rows(2).FindNext(After:=rDef) 'find next definition
Loop Until rDef Is Nothing Or rDef.Address = sFirst
Next
End With
End Sub
Take a look at this macro and see what you think about it. I copied your sample set and was able to duplicate your desired results using nested for loops. Let me know if anything needs clarification.
Option Explicit
Sub customTransposing()
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim startingRow As Integer
Dim startingColumn As Integer
Dim numberOfPoints As Integer
Dim numberOfEntries As Integer
Dim numberOfGroups As Integer
Dim outputRowOffset As Integer
' -------------------------------------------------------------------------------------------
' User Variables
' -------------------------------------------------------------------------------------------
startingRow = 3
startingColumn = 1
numberOfPoints = 4 ' The number of test points i.e. A B C D
numberOfEntries = 0
numberOfGroups = 3
outputRowOffset = 10
' -------------------------------------------------------------------------------------------
' Counts the number of entries in the first column
' this section could most likely be improved
Cells(startingRow, startingColumn).Select
Do Until IsEmpty(ActiveCell)
If Not IsEmpty(ActiveCell) Then
numberOfEntries = numberOfEntries + 1
End If
ActiveCell.Offset(1, 0).Select
Loop
For j = 0 To numberOfEntries - 1
For k = 0 To numberOfGroups - 1
For i = 0 To numberOfPoints - 1
' first column
Cells(startingRow + numberOfEntries + (j * numberOfPoints * numberOfGroups) + outputRowOffset + i + k * numberOfPoints, startingColumn).Value = Cells(startingRow + j, startingColumn)
' second column
Cells(startingRow + numberOfEntries + (j * numberOfPoints * numberOfGroups) + outputRowOffset + i + k * numberOfPoints, startingColumn + 1).Value = Cells(startingRow + j, startingColumn + 2 + i + k * (numberOfGroups + 2))
' third column
Cells(startingRow + numberOfEntries + (j * numberOfPoints * numberOfGroups) + outputRowOffset + i + k * numberOfPoints, startingColumn + 2).Value = Cells(startingRow - 1, startingColumn + 2 + i)
' fourth column
Cells(startingRow + numberOfEntries + (j * numberOfPoints * numberOfGroups) + outputRowOffset + i + k * numberOfPoints, startingColumn + 3).Value = Cells(startingRow + j, startingColumn + 1 + k * (numberOfGroups + 2))
Next i
Next k
Next j
End Sub

Macro to export all n set of values combinations of x>n values of range

I need a macro to exports combinations from a range of many sets of values .
The sets of exporting combs will be smaler than the data range sets .
For examble lets say that i need all 2 set of values combinations of a 3 set of values in a data range .
DATA____ EXPORT
A B C____ AB AC BC
B B A____ BB BA BA
-
All the values of the data will be in different cels each one but the combs values must be in one cell each time.
Also the exports must be in horizontial as the example .
This is a code that ifound on web little close for me , but i cannot edit this to use it .
enter code here
Sub comb()
Dim vElements As Variant, vresult As Variant
Dim lRow As Long, i As Long
vElements = Application.Transpose(Range("A1", Range("A1").End(xlDown)))
Columns("C:Z").Clear
lRow = 1
For i = 1 To UBound(vElements)
ReDim vresult(1 To i)
Call CombinationsNP(vElements, i, vresult, lRow, 1, 1)
Next i
End Sub
Sub CombinationsNP(vElements As Variant, p As Long, vresult As Variant, lRow As Long,
iElement As Integer, iIndex As Integer)
Dim i As Long
For i = iElement To UBound(vElements)
vresult(iIndex) = vElements(i)
If iIndex = p Then
lRow = lRow + 1
Range("C" & lRow).Resize(, p) = vresult
Else
Call CombinationsNP(vElements, p, vresult, lRow, i + 1, iIndex + 1)
End If
Next i
End Sub
Thank you very much and sorry for my english .
I wonder if it was more convenient to use a new Sheet/ Range with cell reference
((= Sheet1! $A1 & Sheet1! B1)) this is three lines then copy
Sub Sub export_01()
Dim aStart, aExport
Dim aRow As Integer
aRow = ActiveSheet.Range("A65536").End(xlUp).Row
aStart = 1
aExport = 5
For i = 1 To aRow
Cells(i, aExport).Value = Cells(i, aStart) & Cells(i, aStart + 1)
Cells(i, aExport + 1).Value = Cells(i, aStart) & Cells(i, aStart + 2)
Cells(i, aExport + 2).Value = Cells(i, aStart + 1) & Cells(i, aStart + 2)
Next i
End Sub()
This seems to me simply use a second for loop
dim aStartend = 1
For i = 1 To aRow
For ii = 0 To 5 ' starts whist 0 to 5 = 6 time
Cells(i, aExport+ii).Value = Cells(i, aStart) & Cells(i,aStartend + ii)
--
--
next ii
next i