I've one workbook with 170K rows, I will delete all rows when the result between cells is 0,
For those operation, normally I use the code below, but with 170K (the rows will be deleted are 90K) the code run very slowly.
Someone know another way more performance.
Thank
Last = Cells(Rows.Count, "K").End(xlUp).Row
For i = Last To 2 Step -1
If (Cells(i, "K").Value + Cells(i, "L").Value) < 1 Then
Cells(i, "A").EntireRow.Delete
End If
Next i
As long as your fine putting the data on a new tab, the code below will do everything you need in 1.5 seconds.
Sub ExtractRows()
Dim vDataTable As Variant
Dim vNewDataTable As Variant
Dim vHeaders As Variant
Dim lastRow As Long
Dim i As Long, j As Long
Dim Counter1 As Long, Counter2 As Long
With Worksheets(1)
lastRow = .Cells(Rows.Count, "K").End(xlUp).row
vHeaders = .Range("A1:L1").Value2
vDataTable = .Range("A2:L" & lastRow).Value2
End With
For i = 1 To UBound(vDataTable)
If vDataTable(i, 11) + vDataTable(i, 12) > 0 Then
Counter1 = Counter1 + 1
End If
Next
ReDim vNewDataTable(1 To Counter1, 1 To 12)
For i = 1 To UBound(vDataTable)
If vDataTable(i, 11) + vDataTable(i, 12) > 0 Then
Counter2 = Counter2 + 1
For j = 1 To 12
vNewDataTable(Counter2, j) = vDataTable(i, j)
Next j
End If
Next
Worksheets.Add After:=Worksheets(1)
With Worksheets(2)
.Range("A1:L1") = vHeaders
.Range("A2:L" & Counter1 + 1) = vNewDataTable
End With
End Sub
Here, my approach for your problem according to rwilson's idea.
I already tested it. It very very reduce executing time. Try it.
Sub deleteRow()
Dim newSheet As Worksheet
Dim lastRow, newRow As Long
Dim sheetname As String
Dim startTime As Double
sheetname = "sheetname"
With Sheets(sheetname)
Set newSheet = ThisWorkbook.Worksheets.Add(After:=Sheets(.Name))
'Firstly copy header
newSheet.Rows(1).EntireRow.Value = .Rows(1).EntireRow.Value
lastRow = .Cells(.Rows.Count, "K").End(xlUp).row
newRow = 2
For row = 2 To lastRow Step 1
If (.Cells(row, "K").Value + .Cells(row, "L").Value) >= 1 Then
newSheet.Rows(newRow).EntireRow.Value = .Rows(row).EntireRow.Value
newRow = newRow + 1
End If
Next row
End With
Application.DisplayAlerts = False
Sheets(sheetname).Delete
Application.DisplayAlerts = True
newSheet.Name = sheetname
End Sub
Here is a non-VBA option you can try:
In column M compute the sum of columns K and L
Highlight column M and the click Find and select > Find
Type in 0 in the Find what box and also select values in the Look in box
Select Find all and in the box that shows the found items select all entires (click in the box and press CTRL + A)
On the ribbon select Delete and then Delete sheet rows
Now manually delete column M
I haven't tried this with 170k+ rows but maybe worth assessing performance versus the VBA loop.
thank at all for your ideas but the really fast code is: use an array tu populate whit the correct date and replare all table of the end sort the table:
Sub Macro13(control As IRibbonControl)
Dim avvio As Date
Dim arresto As Date
Dim tempo As Date
Application.ScreenUpdating = False
Application.Calculation = xlManual
avvio = Now()
Dim sh As Worksheet
Dim arng As Variant
Dim arrdb As Variant
Dim UR As Long, x As Long, y As Long
Dim MyCol As Integer
Set sh = Sheets("Rol_db")
MyCol = 1
sh.Select
UR = sh.Cells(Rows.Count, MyCol).End(xlUp).Row
ReDim arrdb(2 To UR, 1 To 12) As Variant
For x = 2 To UR
If Cells(x, 11) + Cells(x, 12) > 0 Then
For y = 1 To 12
arrdb(x, y) = Cells(x, y)
Next y
Else
For y = 1 To 12
arrdb(x, y) = ""
Next y
End If
Next x
sh.Range("A2:L" & UR) = arrdb
arresto = Now()
tempo = arresto - avvio
Debug.Print "Delete empty rows " & tempo
Range("A2:L" & UR).Sort key1:=Range("A2:L" & UR), _
order1:=xlAscending, Header:=xlNo
Range("A4").Select
ActiveWindow.FreezePanes = True
conclusioni:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
time for my sheet 170K 00:00:07.
as soon as I have a minute I feel a loop of the columns
Related
My loop seems to create infinite rows and is bugging
For Each Cell In Workbooks(newBook).Sheets(1).Range("A1:A" & lRow)
Checker = Cell.Value
For Counter = 1 To Len(Checker)
If Mid(Checker, Counter, 1) = vbLf Then
holder = Right(Mid(Checker, Counter, Len(Checker)), Len(Checker))
Workbooks(newBook).Sheets(1).Range(Cell.Address).EntireRow.Insert
End If
Next
Next Cell
Use a reverse loop. For i = lRow to 1 Step -1. Also to separate word, you can use SPLIT().
Is this what you are trying?
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long
Dim i As Long, j As Long
Dim Ar As Variant
'~~> Change this to the relevant worksheet
Set ws = Sheet2
With ws
'~~> Find last row in Column A
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Reverse Loop in Column A
For i = lRow To 1 Step -1
'~~> Check if cell has vbLf
If InStr(1, .Cells(i, 1).Value, vbLf) Then
'~~> Split cell contents
Ar = Split(.Cells(i, 1).Value, vbLf)
'~~> Loop through the array from 2nd position
For j = LBound(Ar) + 1 To UBound(Ar)
.Rows(i + 1).Insert
.Cells(i + 1, 1).Value = Ar(j)
Next j
'~~> Replace cells contents with content from array from 1st position
.Cells(i, 1).Value = Ar(LBound(Ar))
End If
Next i
End With
End Sub
BEFORE
AFTER
This is my solution, works with 2 dimensional ranges as well and it works on Selection, so select the range with the cells you want to split and run the code.
Sub splitByNewLine()
Dim pasteCell As Range, rowCumulationTotal As Integer
rowCumulationTotal = 0
Dim arr() As Variant
arr = Selection
Selection.Clear
For i = 1 To UBound(arr)
Dim rowCumulationCurrent As Integer, maxElemsOnRow As Integer
rowCumulationCurrent = 0
maxElemsOnRow = 0
For j = 1 To UBound(arr, 2)
Dim elems() As String, elemCount As Integer
elems = Split(arr(i, j), vbLf)
elemCount = UBound(elems)
For k = 0 To elemCount
Cells(Selection.Row + i + rowCumulationTotal + k - 1, Selection.Column + j - 1) = elems(k)
If maxElemsOnRow < k Then
rowCumulationCurrent = rowCumulationCurrent + 1
maxElemsOnRow = k
End If
Next k
Next j
rowCumulationTotal = rowCumulationTotal + rowCumulationCurrent
Next i
Exit Sub
End Sub
Input:
Output:
I've written the below code to modify a speadsheet that has tens of thousands of lines. Whenever I run the code, it burns through the lines fast enough, will complete about 10k lines in 3-4 minutes or so. But every time I run it, it gets to about line 25K or so, and crashes, telling me I don't have enough memory, and will suggest upgrading to 64-bit. I have a macro that created the sheet without incident, and it's much more complex, so seems odd this code crashes it. Anything in this code that you'd think would cause my issue? Or is 64-bit likely the right fix?
Sub TPOUploadCADUplicate()
'This takes the TPO Mass upload sheet and duplicates it below for Canada. Unlike above, it doesn't do anything to the US part on top
Dim Answer As String
Dim BigMarkup As Double
Dim CAPrice As Double
Dim Cost As Double
Dim i As Long
Dim rn As Long
Dim rn2 As Long
Dim SKUCount As Double
Dim STMarkup As Double
Dim USPrice As Double
Dim lr As Long
Dim DescLen As Integer
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
'Make sure you didn't accidentally leave the description length column in
If Cells(1, 3) <> "VENDOR # (9 SPACES)" Then
DescLen = MsgBox("Yo, bro. I think you left the description length column in. You want to delete that shit? I can't proceed otherwise.", vbYesNo)
If DescLen = 6 Then
Columns(3).Delete
ElseIf DescLen = 7 Then
Exit Sub
End If
End If
Columns(6).NumberFormat = "#.00"
'Loop through each one, doing the math from the TPO price calculator Connie has
If Cells(2, 1) = "" Then Exit Sub
rn = Cells(1, 1).End(xlDown).Row
rn2 = rn + 1
rn = 2
SKUCount = rn2 - rn
For i = 1 To SKUCount
Application.StatusBar = "Progress: " & i & " of " & SKUCount & " - " & Format(i / SKUCount, "0%")
Rows(rn2).Value = Rows(rn).Value
USPrice = Cells(rn, 4)
If USPrice * CAMarkup < 20 Then
CAPrice = Round((USPrice) * CAMarkup, 1) + 0.09
Else
CAPrice = WorksheetFunction.RoundDown((USPrice) * CAMarkup, 0) + 0.99
End If
Cells(rn2, 4) = CAPrice
Cells(rn2, 6).Value = Cells(rn2, 6).Value * CAMarkup
Cells(rn2, 22) = "CAM"
rn = rn + 1
rn2 = rn2 + 1
Next i
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
.StatusBar = False
End With
End Sub
Might be better (faster) to read all the data to an array, then work on the array, before putting it on the sheet after the existing data.
Sub TPOUploadCADUplicate()
Dim ans
Dim CAPrice As Double
Dim SKUCount As Double
Dim STMarkup As Double, CAMarkup As Double
Dim USPrice As Double
Dim DescLen As Integer, ws As Worksheet, arr, lr As Long, lc As Long, r As Long
Set ws = ActiveSheet 'best to be explicit about which sheet you're working with
'Make sure you didn't accidentally leave the description length column in
If ws.Cells(1, 3) <> "VENDOR # (9 SPACES)" Then
ans = MsgBox("Yo, bro. I think you left the description length column in. " & _
"You want to delete that shit? I can't proceed otherwise.", vbYesNo)
If ans <> vbYes Then Exit Sub
ws.Columns(3).Delete
End If
ws.Columns(6).NumberFormat = "#.00"
lr = ws.Cells(Rows.Count, "A").End(xlUp).Row 'last row
If lr = 1 Then Exit Sub 'no data?
lc = ws.Cells(1, Columns.Count).End(xlToLeft).Column 'last column
CAMarkup = 1.1 '<< for example
arr = ws.Range("A2", ws.Cells(lr, lc)).value 'copy the existing data as an array
For r = 1 To UBound(arr, 1) 'loop over the array and make adjustments
USPrice = arr(r, 4)
If USPrice * CAMarkup < 20 Then
CAPrice = Round((USPrice) * CAMarkup, 1) + 0.09
Else
CAPrice = WorksheetFunction.RoundDown((USPrice) * CAMarkup, 0) + 0.99
End If
arr(r, 4) = CAPrice
arr(r, 6) = arr(r, 6) * CAMarkup
arr(r, 22) = "CAM"
Next r
'put the data on the sheet
ws.Cells(lr + 1, "A").Resize(UBound(arr, 1), UBound(arr, 2)).value = arr
End Sub
I have the following issue: In one workbook I have multiple sheets.
On Sheet 2 in column "D" starting on row 2, Is a list of 300+ prefixes of 4 digits long e.g. XFTZ, GHTU, ZAQS etc.
On Sheet 1 in column "R" starting on row 3, Is a list of 1000+ values that can have the following values e.g.: AAAA1234556 and ZAQS12565865.
The first value AAAA...... is allowed, where the second value ZAQS..... Should throw an error message when running the VBA code.
The list of values in both sheets can grow over time, so I would like to avoid hard coding of records. I would expect best solution here is to use something like this:
LastRowNr = Cells(Rows.Count, 1).End(xlUp).Row
Try something like the following, replacing Sheet1 with the name in which the actual data is located
Option Explicit
Private Sub searchPrefix()
Dim RangeInArray() As Variant
Dim LastRow1 As Long
Dim LastRow2 As Long
Dim tmpSrch As String
Dim i As Long
LastRow1 = Worksheets("Sheet1").Cells(Rows.Count, 18).End(xlUp).Row
LastRow2 = Worksheets("PREFIXES").Cells(Rows.Count, 4).End(xlUp).Row
RangeInArray = Application.Transpose(Worksheets("PREFIXES").Range("D1:D" & LastRow2).Value)
For i = 3 To LastRow1
If Len(Worksheets("Sheet1").Cells(i, 18).Value) >= 3 Then
tmpSrch = Left(Worksheets("Sheet1").Cells(i, 18).Value, 4) '18: column R
If IsInArray(tmpSrch, RangeInArray) Then
Worksheets("Sheet1").Cells(i, 18).Interior.ColorIndex = xlNone
Worksheets("Sheet1").Cells(i, 18).Font.ColorIndex = 0
Worksheets("Sheet1").Cells(i, 18).Font.Bold = False
Else
Worksheets("Sheet1").Cells(i, 18).Interior.Color = RGB(252, 134, 75)
Worksheets("Sheet1").Cells(i, 18).Font.Color = RGB(181, 24, 7)
Worksheets("Sheet1").Cells(i, 18).Font.Bold = True
End If
End If
Next
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function
Option Explicit
Sub searchPrefix()
Sheets("PREFIXES").Select
Dim CellCntnt As String
Dim tmpSrch As String
Dim isFound As Boolean
isFound = False
Dim QtySrchChar As Integer
QtySrchChar = 4
Dim Cnt As Integer
Cnt = 0
Dim Tag As Integer
Cells.Range("A1").Select
Do Until IsEmpty(ActiveCell)
Cnt = Cnt + 1
ActiveCell.Offset(1, 0).Select
Loop
For Tag = 1 To Cnt - 1
CellCntnt = Cells(1 + i, 1).Value
tmpSrch = Left(CellCntnt, QtySrchChar)
Cells.Range("G1").Select
Do Until IsEmpty(ActiveCell)
If Left(ActiveCell.Value, QtySrchChar) = tmpSrch Then
QtySrchChar = QtySrchChar + 1
tmpSrch = Left(CellCntnt, QtySrchChar)
isFound = True
MsgBox ("True Tags introduced with Std.Prefix " & tmpSrch)
End If
If isFound Then
isFound = False
MsgBox ("False Tags introduced with Std.Prefix " & tmpSrch)
Cells.Range("G1").Select
Else
ActiveCell.Offset(1, 0).Select
End If
Loop
Next Tag
End Sub
I work for a construction company. I have been writing a macro for the inventory department which can retrieve the latest date on which a particular type of material was supplied to a specific Flat No. at site.
The code which I have is doing the job but it's taking very long to compute all the results. Can anyone tell me how to make this go even faster.
Following is the code:
Sub FillTopSheet()
'Designing a loop to move through the fill data on Top Sheet
Application.ScreenUpdating = False
'Declaring variables for counts
Dim Flat_Row_Num As Long
Dim Tower_Col_Num As Long
Dim InventoryWs As Worksheet
'Debug.Print Application.Workbooks("The Crest DLF Project-In-Out Inventory Data.xlsx").Worksheets("Material-Out").Name
Set InventoryWs = Application.Workbooks("The Crest DLF Project-In-Out Inventory Data.xlsx").Worksheets("Material-Out")
Dim Lookup_Start_Row As Long
Dim Lookup_End_Row As Long
'Lookup_Start_Row = 4
'
'Select Case Application.ThisWorkbook.ActiveSheet.Name
' Case "Kitchen Carcass"
' Do Until InventoryWs.Cells(Lookup_Start_Row, 2).Value = "Kitchen Carcass"
' Lookup_Start_Row = Lookup_Start_Row + 1
' Loop
'
' Lookup_End_Row = Lookup_Start_Row
'
' Do While InventoryWs.Cells(Lookup_End_Row, 2).Value = "Kitchen Carcass"
' Lookup_End_Row = Lookup_End_Row + 1
'
' Loop
'
' Lookup_End_Row = Lookup_End_Row - 1
'
'End Select
Debug.Print Lookup_Start_Row
Debug.Print Lookup_End_Row
Lookup_Start_Row = 6162
Lookup_End_Row = 14754
Flat_Row_Num = 5
Tower_Col_Num = 5
Do Until Tower_Col_Num > 13
Do Until Flat_Row_Num > 154
If Application.ThisWorkbook.ActiveSheet.Cells(Flat_Row_Num, Tower_Col_Num - 1).Value <> "" Then
Do Until Lookup_Start_Row = Lookup_End_Row
If Application.ThisWorkbook.ActiveSheet.Cells(Flat_Row_Num, Tower_Col_Num - 1).Value = _
InventoryWs.Cells(Lookup_Start_Row, 8).Value Then
Application.ThisWorkbook.ActiveSheet.Cells(Flat_Row_Num, Tower_Col_Num).Value = _
InventoryWs.Cells(Lookup_Start_Row, 6).Value
GoTo RowReset
Else
Application.ThisWorkbook.ActiveSheet.Cells(Flat_Row_Num, Tower_Col_Num).Value = "NA"
End If
Lookup_Start_Row = Lookup_Start_Row + 1
Loop
Lookup_Start_Row = 6162
RowReset:
Lookup_Start_Row = 6162
End If
Flat_Row_Num = Flat_Row_Num + 1
Loop
Flat_Row_Num = 5
Tower_Col_Num = Tower_Col_Num + 2
Loop
Application.ScreenUpdating = True
End Sub
Could be something like this but indexes (i,j,k) might be mixed up.
Would be much easier if you could post your input and desired output (eg some screenshot)
Sub FillTopSheet()
'Declaring variables for counts
Dim Flat_Row_Num As Long
Dim Tower_Col_Num As Long
Dim InventoryWs As Worksheet, Ws As Worksheet
Dim ArrLookUp() As Variant, ArrData() As Variant
Dim Lookup_Start_Row As Long, Lookup_End_Row As Long, i As Long, j As Long, k As Long
Dim FlatNo As String
'Designing a loop to move through the fill data on Top Sheet
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
'Debug.Print Application.Workbooks("The Crest DLF Project-In-Out Inventory Data.xlsx").Worksheets("Material-Out").Name
Set InventoryWs = Application.Workbooks("The Crest DLF Project-In-Out Inventory Data.xlsx").Worksheets("Material-Out")
Debug.Print Lookup_Start_Row
Debug.Print Lookup_End_Row
Lookup_Start_Row = 6162
Lookup_End_Row = 14754
Flat_Row_Num = 5
Tower_Col_Num = 2 'Start in Tower A "Flats No. column
With InventoryWs
ArrLookUp = .Range(.Cells(Lookup_Start_Row, 6), .Cells(Lookup_End_Row, 8))
End With
With Ws
ArrData = .Range(.Cells(Flat_Row_Num, Tower_Col_Num), .Cells(154, 13))
End With
For i = LBound(ArrData, 2) To UBound(ArrData, 2) Step 2
For j = LBound(ArrData) To UBound(ArrData)
'loop through "towers" Array
FlatNo = ArrData(j, i) 'take one flat no
If FlatNo <> "" Then
For k = LBound(ArrLookUp) To UBound(ArrLookUp)
'look for this flat no in other array
If FlatNo = ArrLookUp(k, 3) Then
'first match = take Date from other array
'dates sorted descending
ArrData(j, i + 1) = ArrLookUp(k, 1)
'found what was looking for, get out of loop
Exit For
End If
Next k
End If
Next j
Next i
With Ws
'range must be same as when you set the array earlier. But if that range contains some formulas they'll be overwriten with values
'in that case you can loop through array and take out only dates
.Range(.Cells(Flat_Row_Num, Tower_Col_Num), .Cells(154, 13)) = ArrData
End With
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Edit
This still might need some adjustment to fit in your ranges
Check ranges in ArrLookUp = .Range(.Cells(Lookup_Start_Row, 6), .Cells(Lookup_End_Row, 8)) and ArrLookUp = .Range(.Cells(Lookup_Start_Row, 6), .Cells(Lookup_End_Row, 8))
It takes "Towers" and looks for "Flats No." in other sheet. At first match date is taken from other sheet.
I am not sure if the title is correct. Please correct me if you have a better idea.
Here is my problem: Please see the picture.
This excel sheet contains only one column, let's say ColumnA. In ColumnA there are some cells repeat themselvs in the continued cells twice or three times (or even more).
I want to have the excel sheet transformed according to those repeated cells. For those items which repeat three times or more, keep only two of them.
[Shown in the right part of the picture. There are three Bs originally, target is just keep two Bs and delete the rest Bs.]
It's a very difficult task for me. To make it easier, it's no need to delete the empty rows after transformation.
Any kind of help will be highly appreciated. Thanks!
#
Update:
Please see the picture. Please dont delete the items if they show again...
EDITED - SEE BELOW Try this. Data is assumed to be in "Sheet1", and ordered data is written to "Results". I named your repeted data (A, B, C, etc) as sMarker, and values in between as sInsideTheMarker. If markers are not consecutive, the code will fail.
Private Sub ReOrderData()
Dim lLastRow As Long
Dim i As Integer
Dim a As Integer
Dim j As Integer
Dim sMarker As String
Dim sInsideTheMarker As String
'Get number of rows with data:
lLastRow = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
j = 0
k = 1
a = 2
'Scan all rows with data:
For i = 1 To lLastRow
If (Worksheets("Sheet1").Cells(i + 1, 1).Value = Worksheets("Sheet1").Cells(i, 1).Value) Then 'If two consecutive cells holds the same value
j = j + 1
If j = 1 Then
k = k + 1
a = 2
sMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Results").Cells(k, 1).Value = sMarker
End If
Else 'If not same values in consecutive cells
sInsideTheMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Results").Cells(k, a).Value = sInsideTheMarker
a = a + 1
j = 0
End If
Next i
End Sub
EDITION: If you want results in the same sheet ("Sheet1"), and keep the empty rows for results to look exactly as your question, try the following
Private Sub ReOrderData()
Dim lLastRow As Long
Dim i As Integer
Dim a As Integer
Dim j As Integer
Dim sMarker As String
Dim sInsideTheMarker As String
'Get number of rows with data:
lLastRow = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
j = 0
k = 1
a = 5
'Scan all rows with data:
For i = 1 To lLastRow
If (Worksheets("Sheet1").Cells(i + 1, 1).Value = Worksheets("Sheet1").Cells(i, 1).Value) Then 'If two consecutive cells holds the same value
j = j + 1
If j = 1 Then
k = i
a = 5
sMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Sheet1").Cells(k, 4).Value = sMarker
End If
Else 'If not same values in consecutive cells
sInsideTheMarker = Worksheets("Sheet1").Cells(i, 1).Value
Worksheets("Sheet1").Cells(k, a).Value = sInsideTheMarker
a = a + 1
j = 0
End If
Next i
End Sub
If you can delete the values that have more than two counts, then I suggest that this might work:
Sub count_macro()
Dim a As Integer
Dim b As Integer
a = 1
While Cells(a, 1) <> ""
b = WorksheetFunction.CountIf(Range("A1:A1000"), Cells(a, 1))
If b > 2 Then
Cells(a, 1).Delete Shift:=xlUp
End If
b = 0
a = a + 1
Wend
End Sub
This should do it. It takes input in column A starting in Row 2 until it ends, and ignores more than 2 same consecutive values. Then it copies them in sets and pastes them transposed. If your data is in a different column and row, change the sourceRange variable and the i variable accordingly.
Sub SETranspose()
Application.ScreenUpdating = False
Dim sourceRange As range
Dim copyRange As range
Dim myCell As range
Set sourceRange = range("A2", Cells(Rows.count, 1).End(xlUp))
Dim startCell As range
Set startCell = sourceRange(1, 1)
Dim i As Integer
Dim haveTwo As Boolean
haveTwo = True
For i = 3 To Cells(Rows.count, 1).End(xlUp).Row + 1
If Cells(i, 1).Value = startCell.Value Then
If haveTwo Then
range(startCell, Cells(i, 1)).Copy
startCell.Offset(0, 4).PasteSpecial Transpose:=True
Application.CutCopyMode = False
haveTwo = False
End If
End If
'if the letter changes or end of set, then copy the set over
'If LCase(Left(Cells(i, 1).Value, 1)) <> LCase(startCell.Value) Or _
'i = Cells(Rows.count, 1).End(xlUp).Row + 1 Then
If Len(Cells(i, 1).Value) > 1 Then
Set copyRange = Cells(i, 1)
copyRange.Copy
Cells(startCell.Row, Columns.count).End(xlToLeft).Offset(0, 1).PasteSpecial
Application.CutCopyMode = False
'Set startCell = sourceRange(i - 1, 1)
ElseIf Len(Cells(i, 1).Value) = 1 And Cells(i, 1).Value <> startCell.Value Then
Set startCell = sourceRange(i - 1, 1)
haveTwo = True
End If
Next i
'clear up data
Set sourceRange = Nothing
Set copyRange = Nothing
Set startCell = Nothing
Application.ScreenUpdating = True
End Sub