VBA to seperate and transpose data into rows [duplicate] - excel

This question already has answers here:
Split comma separated entries to new rows [closed]
(2 answers)
Closed 1 year ago.
I currently have this data in a sheet
Col A Col B Col C
1 A angry birds, gaming
2 B nirvana,rock,band
What I want to do is split the comma separated entries in the third column and insert in new rows like below:
Col A Col B Col C
1 A angry birds
1 A gaming
2 B nirvana
2 B rock
2 B band
I am sure this can be done with VBA but couldn't figure it out myself.

variant using Scripting.Dictionary
Sub ttt()
Dim dic As Object: Set dic = CreateObject("Scripting.Dictionary")
Dim x&, cl As Range, rng As Range, k, s
Set rng = Range([C1], Cells(Rows.Count, "C").End(xlUp))
x = 1 'used as a key for dictionary and as row number for output
For Each cl In rng
For Each s In Split(cl.Value2, ",")
dic.Add x, Cells(cl.Row, "A").Value2 & "|" & _
Cells(cl.Row, "B").Value2 & "|" & LTrim(s)
x = x + 1
Next s, cl
For Each k In dic
Range(Cells(k, "A"), Cells(k, "C")).Value2 = Split(dic(k), "|")
Next k
End Sub
source:
result:

If you have a substantial amount of data, you willfind working with arrays beneficial.
Sub Macro2()
Dim i As Long, j As Long, rws As Long
Dim inp As Variant, outp As Variant
With Worksheets("sheet2")
inp = .Range(.Cells(1, "A"), .Cells(.Rows.Count, "C").End(xlUp)).Value2
For i = LBound(inp, 1) To UBound(inp, 1)
rws = rws + UBound(Split(inp(i, 3), ",")) + 1
Next i
ReDim outp(1 To rws, 1 To 3)
rws = 0
For i = LBound(inp, 1) To UBound(inp, 1)
For j = 0 To UBound(Split(inp(i, 3), ","))
rws = rws + 1
outp(rws, 1) = inp(i, 1)
outp(rws, 2) = inp(i, 2)
outp(rws, 3) = Trim(Split(inp(i, 3), ",")(j))
Next j
Next i
.Cells(1, "A").Resize(UBound(outp, 1), UBound(outp, 2)) = outp
End With
End Sub

This is not a polished solution, but I need to spend some time with the wife.
But still another way of thinking about it.
This code assumes that the sheet is called Sheet4 and the range that needs to be split is col C.
Dim lastrow As Integer
Dim i As Integer
Dim descriptions() As String
With Worksheets("Sheet4")
lastrow = .Range("C1").End(xlDown).Row
For i = lastrow To 2 Step -1
If InStr(1, .Range("C" & i).Value, ",") <> 0 Then
descriptions = Split(.Range("C" & i).Value, ",")
End If
For Each Item In descriptions
.Range("C" & i).Value = Item
.Rows(i).Copy
.Rows(i).Insert
Next Item
.Rows(i).EntireRow.Delete
Next i
End With

This will do what you want.
Option Explicit
Const ANALYSIS_ROW As String = "C"
Const DATA_START_ROW As Long = 1
Sub ReplicateData()
Dim iRow As Long
Dim lastrow As Long
Dim ws As Worksheet
Dim iSplit() As String
Dim iIndex As Long
Dim iSize As Long
'Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
With ThisWorkbook
.Worksheets("Sheet1").Copy After:=.Worksheets("Sheet1")
Set ws = ActiveSheet
End With
With ws
lastrow = .Cells(.Rows.Count, ANALYSIS_ROW).End(xlUp).Row
End With
For iRow = lastrow To DATA_START_ROW Step -1
iSplit = Split(ws.Cells(iRow, ANALYSIS_ROW).Value2, ",")
iSize = UBound(iSplit) - LBound(iSplit) + 1
If iSize = 1 Then GoTo Continue
ws.Rows(iRow).Copy
ws.Rows(iRow).Resize(iSize - 1).Insert
For iIndex = LBound(iSplit) To UBound(iSplit)
ws.Cells(iRow, ANALYSIS_ROW).Offset(iIndex).Value2 = iSplit(iIndex)
Next iIndex
Continue:
Next iRow
Application.CutCopyMode = False
Application.Calculation = xlCalculationAutomatic
'Application.ScreenUpdating = True
End Sub

Related

sorting with vba

please help i want to sort the name column such that each name starts after every blank cell.
I want it look something like this..pls help it's a pretty long column
Option Explicit
Sub SetNamePosition()
Dim arr As Variant
Dim i As Long: i = 1 ' for Loop
Dim j As Long: j = 1 ' for Array
Dim lastRow As Long: lastRow = Cells(Rows.Count, 1).End(xlUp).Row
Dim rngColB As Range: Set rngColB = Range("B2:B" & lastRow)
Dim rngNames As Range: Set rngNames = Range("C1") ' Temporary range
' Get column B names only
rngColB.SpecialCells(xlCellTypeConstants, 2).Copy
rngNames.PasteSpecial (xlPasteValues)
Application.CutCopyMode = False
Set rngNames = Range(rngNames, rngNames.End(xlDown))
' Load rngNames to array
arr = Application.Transpose(rngNames)
' Clear rng of column B and rngNames
rngColB.Clear
rngNames.Clear
' Insert names
For i = 2 To lastRow
' set name
Cells(i, 1).Offset(0, 1).Value = arr(j)
' find next cell
i = Cells(i, 1).End(xlDown).Row + 1
j = j + 1
Next i
End Sub
I's probably better to remove the empty ranges before making the array, but here's one way to distribute the names:
Loading the range ito an array, then go through the numbers and look for empty ranges.
This assumes that we are working with column "A" and "B" (1 and 2), starting at the top.
Sub test()
Dim arr As Variant
Dim lastRow As Long, i As Long, j As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
arr = Application.Transpose(Range("B2:B" & lastRow))
Range("B2:B" & lastRow).Clear
j = 1
For i = 2 To lastRow
Cells(i, 2) = arr(j)
j = j + 1
If j >= UBound(arr) Then Exit For
While arr(j) = "" And j < UBound(arr)
j = j + 1
Wend
While Not Cells(i, 1).Value = ""
i = i + 1
Wend
Next i
End Sub
Any leftover names will be removed

Split cells by line break while keeping other data

I have multiple rows in a spreadsheet set up like the following:
TEST 1 Y N TEST_1 1234 Derived
TEST_2 56
I need to split the cells that have a line break while copying the remaining cells into the new row:
TEST 1 Y N TEST_1 1234 Derived
TEST 1 Y N TEST_2 56 Derived
I tested code by changing line breaks to commas (I don't know the VBA symbol for linebreak). The code I tried only works for one column E, not Column F:
Sub splitByCol()
Dim r As Range, i As Long, ar
Set r = Worksheets("Sheet1").Range("E999999:F999999").End(xlUp)
Do While r.row > 1
ar = Split(r.value, ",")
If UBound(ar) >= 0 Then r.value = ar(0)
For i = UBound(ar) To 1 Step -1
r.EntireRow.Copy
r.Offset(1).EntireRow.Insert
r.Offset(1).value = ar(i)
Next
Set r = r.Offset(-1)
Loop
End Sub
I just did a brief test, might not be perfect. If you have a ton of rows and columns this might be a tad slow aswell.
Dim rowiter As Long
Dim coliter As Long
Dim lastrow As Long
Dim lastcol As Long
Dim rowcount As Long
Dim rowadd As Boolean
With ActiveSheet
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
lastcol = .Cells.Find(What:="*", after:=ActiveSheet.Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Column
rowcount = lastrow + 1
For rowiter = 1 To lastrow
rowadd = False
For coliter = 1 To lastcol
If InStr(1, .Cells(rowiter, coliter), vbLf) Then
.Cells(rowcount, coliter).Value = Split(.Cells(rowiter, coliter), vbLf)(1)
.Cells(rowiter, coliter).Value = Split(.Cells(rowiter, coliter), vbLf)(0)
rowadd = True
End If
Next
If rowadd = True Then
For coliter = 1 To lastcol
If .Cells(rowcount, coliter).Value = "" Or IsNull(.Cells(rowcount, coliter).Value) Then
.Cells(rowcount, coliter).Value = .Cells(rowiter, coliter).Value
End If
Next
rowcount = rowcount + 1
End If
rowadd = False
Next
.Range(Cells(1, 1), Cells(rowcount, lastcol)).Sort Key1:=Columns("A"), Order1:=xlDescending
End With
Actually you were almost there:
You need to split by vbLf instead of ","
You need to split column E and F into seperate arrays
So you end up with:
Option Explicit
Sub splitByCol()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim CurrentCell As Range
Set CurrentCell = ws.Range("E" & ws.Rows.Count).End(xlUp)
Dim ArrE As Variant 'split array for column E
Dim ArrF As Variant 'split array for column F
Do While CurrentCell.Row > 1
ArrE = Split(CurrentCell.Value, vbLf)
ArrF = Split(CurrentCell.Offset(ColumnOffset:=1).Value, vbLf)
If UBound(ArrE) >= 0 Then CurrentCell.Value = ArrE(0)
If UBound(ArrF) >= 0 Then CurrentCell.Offset(ColumnOffset:=1).Value = ArrF(0)
Dim i As Long
For i = UBound(ArrE) To 1 Step -1
CurrentCell.EntireRow.Copy
CurrentCell.Offset(1).EntireRow.Insert
CurrentCell.Offset(1).Value = ArrE(i)
If UBound(ArrF) >= i Then
CurrentCell.Offset(1, 1).Value = ArrF(i)
Else
CurrentCell.Offset(1, 1).Value = vbNullString
End If
Next i
Set CurrentCell = CurrentCell.Offset(-1)
Loop
End Sub
Input
Output

Error 1004 application defined or object defined error

Here the code:
Sub deleterow2()
Dim a As Integer
Dim n As Integer
Dim c As Integer
LastRow = Range("F" & Rows.Count).End(xlUp).Row
For n = 0 To LastRow
a = 1
c = 0
Do Until c = 1
Cells(n + a, 6).Select
If Selection.value = Cells(n, 6) And Selection.value > 30 Then
Selection.EntireRow.Delete
Else
c = 1
End If
a = a + 1
Loop
Next n
End Sub
What s wrong with that?
Please see below corrected code... instead of starting n at 0, start with a at 0. Plus, avoid using .Select everything... and you should try to declare your ranges fully:
Sub deleterow222()
Dim lastRow As Long, R As Long
Dim ws As Worksheet: Set ws = ActiveWorkbook.ActiveSheet
Dim idColumn as Long: idColumn = 6
Dim diffColumn as Long: diffColumn = 19
lastRow = ws.Range("F" & ws.Rows.Count).End(xlUp).Row
For R = lastRow To 2 Step -1
With ws
If .Cells(R, idColumn) = .Cells(R - 1, idColumn) And .Cells(R, diffColumn) > 30 Then
.Cells(R, idColumn).EntireRow.Delete
End If
End With
Next R
End Sub
Some Tips:
You could not use n = 0 because you will create an error. Rows start from 1.
When you loop in order to delete you start from the end.
For n = LastRow To 1 Step -1
If there are a lot of lines and you will use For Loop declare you variable As Long.
If you have a lot of rows it s better to use an Array.
Try to avoid .Select by creating a With Statement with the sheet name
With ThisWorkbook.Worksheets("Sheet1") and refer to cell using .Cells(n + A, 6).Value
Do Until should start also from high to low due to the fact that you go from bottom to top.
enter image description here
Sub deleterow2()
Dim lastRow As Long, R As Long
Dim ws As Worksheet: Set ws = ActiveWorkbook.ActiveSheet
lastRow = ws.Range("F" & ws.Rows.Count).End(xlUp).Row
For R = lastRow To 2 Step -1
With ws
If .Cells(R, 6).value = .Cells(R - 1, 6) And .Cells(R, 19).value > 30 Then
.Cells(R, 6).EntireRow.Delete
End If
End With
Next R
End Sub

Finding duplicates in all columns with varying row numbers

I am new to VBA and was trying to write a macro to check duplicates among a column. I have values in columns from A to Z with varying last row number, some may be 5 while some may be 10. Is there any way to check if duplicate value exist among a column and then print "duplicate" on the first row (I dont have any values in the first row for all the columns). I need this for varying last row and last column number.
You can try:
Option Explicit
Public Sub Get_Unique_Count_Paste_Array()
Dim Ob As Object
Dim rng As Range
Dim i As Long
Dim str As String
Dim LR As Long
Dim Item As Variant
With Worksheets("Sheet1")
For i = 1 To 26
Set Ob = CreateObject("scripting.dictionary")
LR = .Cells(.Rows.Count, i).End(xlUp).Row
For Each rng In .Range(Cells(2, i), Cells(LR, i))
str = Trim(rng.Value)
If Len(str) > 0 Then
Ob(str) = Ob(str) + 1
End If
Next rng
For Each Item In Ob.keys
If .Cells(1, i).Value = "" Then
.Cells(1, i).Value = Item
ElseIf .Cells(1, i).Value <> "" Then
.Cells(1, i).Value = .Cells(1, i).Value & ", " & Item
End If
Next Item
Next i
End With
End Sub
Edited Version:
Option Explicit
Public Sub Get_Unique_Count_Paste_Array()
Dim Ob As Object
Dim rng As Range
Dim i As Long
Dim str As String
Dim LR As Long
Dim Item As Variant
With Worksheets("Sheet1")
For i = 1 To 26
Set Ob = CreateObject("scripting.dictionary")
LR = .Cells(.Rows.Count, i).End(xlUp).Row
For Each rng In .Range(Cells(2, i), Cells(LR, i))
str = Trim(rng.Value)
If Len(str) > 0 Then
Ob(str) = Ob(str) + 1
End If
Next rng
For Each Item In Ob.keys
If .Cells(1, i).Value = "" And Ob(Item) > 1 Then
.Cells(1, i).Value = "Duplicate"
Exit For
End If
Next Item
Next i
End With
End Sub
A slight alteration of #error 1004's idea
Private d As Scripting.Dictionary
Private s As String
Function Get_Dupe_Summary(rngInput As Excel.Range) as string
Dim c As Excel.Range
Set d = New Scripting.Dictionary
For Each c In rngInput.Cells
If d.Exists(c.Value) Then
Get_Dupe_Summary = Get_Dupe_Summary & _
IIf(Len(Get_Dupe_Summary) > 0, ",", "") & _
"Dupe : " & c & " on row " & c.Row
Else
d.Add c.Value, 1
End If
Next c
End Function

Excel macro -Split comma separated entries to new rows [duplicate]

This question already has answers here:
Split comma separated entries to new rows [closed]
(2 answers)
Closed 1 year ago.
I currently have this data in a sheet
Col A Col B Col C
1 A angry birds, gaming
2 B nirvana,rock,band
What I want to do is split the comma separated entries in the third column and insert in new rows like below:
Col A Col B Col C
1 A angry birds
1 A gaming
2 B nirvana
2 B rock
2 B band
I am sure this can be done with VBA but couldn't figure it out myself.
variant using Scripting.Dictionary
Sub ttt()
Dim dic As Object: Set dic = CreateObject("Scripting.Dictionary")
Dim x&, cl As Range, rng As Range, k, s
Set rng = Range([C1], Cells(Rows.Count, "C").End(xlUp))
x = 1 'used as a key for dictionary and as row number for output
For Each cl In rng
For Each s In Split(cl.Value2, ",")
dic.Add x, Cells(cl.Row, "A").Value2 & "|" & _
Cells(cl.Row, "B").Value2 & "|" & LTrim(s)
x = x + 1
Next s, cl
For Each k In dic
Range(Cells(k, "A"), Cells(k, "C")).Value2 = Split(dic(k), "|")
Next k
End Sub
source:
result:
If you have a substantial amount of data, you willfind working with arrays beneficial.
Sub Macro2()
Dim i As Long, j As Long, rws As Long
Dim inp As Variant, outp As Variant
With Worksheets("sheet2")
inp = .Range(.Cells(1, "A"), .Cells(.Rows.Count, "C").End(xlUp)).Value2
For i = LBound(inp, 1) To UBound(inp, 1)
rws = rws + UBound(Split(inp(i, 3), ",")) + 1
Next i
ReDim outp(1 To rws, 1 To 3)
rws = 0
For i = LBound(inp, 1) To UBound(inp, 1)
For j = 0 To UBound(Split(inp(i, 3), ","))
rws = rws + 1
outp(rws, 1) = inp(i, 1)
outp(rws, 2) = inp(i, 2)
outp(rws, 3) = Trim(Split(inp(i, 3), ",")(j))
Next j
Next i
.Cells(1, "A").Resize(UBound(outp, 1), UBound(outp, 2)) = outp
End With
End Sub
This is not a polished solution, but I need to spend some time with the wife.
But still another way of thinking about it.
This code assumes that the sheet is called Sheet4 and the range that needs to be split is col C.
Dim lastrow As Integer
Dim i As Integer
Dim descriptions() As String
With Worksheets("Sheet4")
lastrow = .Range("C1").End(xlDown).Row
For i = lastrow To 2 Step -1
If InStr(1, .Range("C" & i).Value, ",") <> 0 Then
descriptions = Split(.Range("C" & i).Value, ",")
End If
For Each Item In descriptions
.Range("C" & i).Value = Item
.Rows(i).Copy
.Rows(i).Insert
Next Item
.Rows(i).EntireRow.Delete
Next i
End With
This will do what you want.
Option Explicit
Const ANALYSIS_ROW As String = "C"
Const DATA_START_ROW As Long = 1
Sub ReplicateData()
Dim iRow As Long
Dim lastrow As Long
Dim ws As Worksheet
Dim iSplit() As String
Dim iIndex As Long
Dim iSize As Long
'Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
With ThisWorkbook
.Worksheets("Sheet1").Copy After:=.Worksheets("Sheet1")
Set ws = ActiveSheet
End With
With ws
lastrow = .Cells(.Rows.Count, ANALYSIS_ROW).End(xlUp).Row
End With
For iRow = lastrow To DATA_START_ROW Step -1
iSplit = Split(ws.Cells(iRow, ANALYSIS_ROW).Value2, ",")
iSize = UBound(iSplit) - LBound(iSplit) + 1
If iSize = 1 Then GoTo Continue
ws.Rows(iRow).Copy
ws.Rows(iRow).Resize(iSize - 1).Insert
For iIndex = LBound(iSplit) To UBound(iSplit)
ws.Cells(iRow, ANALYSIS_ROW).Offset(iIndex).Value2 = iSplit(iIndex)
Next iIndex
Continue:
Next iRow
Application.CutCopyMode = False
Application.Calculation = xlCalculationAutomatic
'Application.ScreenUpdating = True
End Sub

Resources