Using VBA arrays to synchronize three sheets into one - arrays

I managed to sync selected data from three sheets into a fourth sheet. But the data doesn't align properly after empty cells beginning with the 14th row.
Now I'm trying to use arrays to align my data better. I have 3 sheets with columns Area, Zone, Employee and 6 numeric columns for each employee.
The data in Area, Zone & Employee is repeating itself in multiple rows so I need to add the numbers for every employee to have the Employee Name displayed only once with added data in other 6 columns.
I don't really have problem with filtering the names and adding data, but I'm not sure how to do it using arrays.
Or if anyone could help me find a mistake in my code that's causing the data to not align properly, I would also appreciate it. Below is my code so far, hopefully it would help.
Private Sub cmd_button1_Click()
Dim WS1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet, ws4 As Worksheet
Set WS1 = Sheets("Sheet2")
Set ws2 = Sheets("Distribution")
Set ws3 = Sheets("Sheet3")
Set ws4 = Sheets("Sheet4")
Dim LastRow As Long
Dim R As Long, LR As Long, n As Long
Application.ScreenUpdating = False
'Getting the row number of last cell
LastRow = ws2.Range("A" & Rows.Count).End(xlUp).Row
'Deleting any previous data from destination sheet
ws2.Range("A2:AX10000").ClearContents
For i = 1 To 10
'If value in V column of the row is "" then copy the row to destination sheet
If WS1.Cells(i, "V").Value = "" Then
WS1.Range("E:E").Copy Destination:=ws2.Range("A1")
WS1.Range("F:F").Copy Destination:=ws2.Range("B1")
WS1.Range("G:G").Copy Destination:=ws2.Range("C1")
WS1.Range("A:A").Copy Destination:=ws2.Range("E1")
WS1.Range("O:O").Copy Destination:=ws2.Range("F1")
WS1.Range("P:P").Copy Destination:=ws2.Range("G1")
WS1.Range("R:R").Copy Destination:=ws2.Range("H1")
WS1.Range("S:S").Copy Destination:=ws2.Range("I1")
WS1.Range("Q:Q").Copy Destination:=ws2.Range("J1")
WS1.Range("T:T").Copy Destination:=ws2.Range("K1")
ws3.Range("E:E").Copy Destination:=ws2.Range("L1")
ws3.Range("F:F").Copy Destination:=ws2.Range("M1")
ws3.Range("G:G").Copy Destination:=ws2.Range("N1")
ws3.Range("A:A").Copy Destination:=ws2.Range("O1")
ws3.Range("S:S").Copy Destination:=ws2.Range("P1")
ws3.Range("T:T").Copy Destination:=ws2.Range("Q1")
ws3.Range("V:V").Copy Destination:=ws2.Range("R1")
ws3.Range("W:W").Copy Destination:=ws2.Range("S1")
ws3.Range("X:X").Copy Destination:=ws2.Range("T1")
ws4.Range("F:F").Copy Destination:=ws2.Range("U1")
ws4.Range("G:G").Copy Destination:=ws2.Range("V1")
ws4.Range("H:H").Copy Destination:=ws2.Range("W1")
ws4.Range("A:A").Copy Destination:=ws2.Range("X1")
ws4.Range("L:L").Copy Destination:=ws2.Range("Y1")
ws4.Range("M:M").Copy Destination:=ws2.Range("Z1")
ws4.Range("N:N").Copy Destination:=ws2.Range("AA1")
ws4.Range("O:O").Copy Destination:=ws2.Range("AB1")
ws4.Range("P:P").Copy Destination:=ws2.Range("AC1")
ws4.Range("Q:Q").Copy Destination:=ws2.Range("AD1")
End If
Next i
LR = Cells(Rows.Count, "C").End(xlUp).Row
Range("A2:AX" & LR).Sort Key1:=Range("A2"), Order1:=xlAscending
For R = 2 To LR
'Count the number of duplicates for third row
n = Application.CountIf(Columns(3), Cells(R, 3).Value)
'Sum up the values for every duplicate
Range("F" & R).Value = Evaluate("=Sum(F" & R & ":F" & R + n - 1 & ")")
Range("G" & R).Value = Evaluate("=Sum(G" & R & ":G" & R + n - 1 & ")")
Range("H" & R).Value = Evaluate("=Sum(H" & R & ":H" & R + n - 1 & ")")
Range("I" & R).Value = Evaluate("=Sum(I" & R & ":I" & R + n - 1 & ")")
Range("J" & R).Value = Evaluate("=Sum(J" & R & ":J" & R + n - 1 & ")")
Range("K" & R).Value = Evaluate("=Sum(K" & R & ":K" & R + n - 1 & ")")
Range("E" & R).Value = Evaluate("=Count(E" & R & ":E" & R + n - 1 & ")")
'Go to next value in third column
R = R + n - 1
Next R
On Error Resume Next
'Remove all duplicates
ws2.Range("$A$1:$K$7979").RemoveDuplicates Columns:=3, Header:=xlYes
On Error GoTo 0
'Fill out the table with values
Columns("A:K").AutoFit
Application.ScreenUpdating = True
Range("A1").Select
End Sub
The code above is for synchronizing the sheets with Distribution and filter the data from Sheet2, and I have 2 more buttons made to filter the other 2 sheets.
The code below is my attempt to align the data but it's not working correctly.
Sub LineEmUp()
Dim i As Long, j As Long, LR As Long
Application.ScreenUpdating = False
LR = Range("C" & Rows.Count).End(xlUp).Row
Columns("A:K").Sort Key1:=Range("A2"), _
Header:=xlYes, OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
Columns("L:T").Sort Key1:=Range("L2"), _
Header:=xlYes, OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
Columns("U:AD").Sort Key1:=Range("U2"), _
Header:=xlYes, OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
i = 2
Do
If Cells(i, "C") > Cells(i, "N") And Cells(i, "C") > "" Then
Cells(i, "A").Resize(1, 10).Insert xlShiftDown
ElseIf Cells(i, "N") > Cells(i, "W") And Cells(i, "N") > "" Then
Cells(i, "L").Resize(1, 10).Insert xlShiftDown
ElseIf Cells(i, "W") > Cells(i, "C") And Cells(i, "W") > "" Then
Cells(i, "U").Resize(1, 10).Insert xlShiftDown
ElseIf Cells(i, "C") < Cells(i, "N") And Cells(i, "C") > "" Then
Cells(i, "L").Resize(1, 10).Insert xlShiftDown
ElseIf Cells(i, "N") < Cells(i, "W") And Cells(i, "N") > "" Then
Cells(i, "U").Resize(1, 10).Insert xlShiftDown
ElseIf Cells(i, "W") < Cells(i, "C") And Cells(i, "W") > "" Then
Cells(i, "A").Resize(1, 10).Insert xlShiftDown
End If
i = i + 1
Loop Until Cells(i, "C") = "" And Cells(i, "W") = ""
Application.ScreenUpdating = True
End Sub
Hope I explained it properly. Thanks

Organization (without unnecessary repetition) is always important in coding, and especially key when troubleshooting. For example, your 29 copy-paste statements can be tidied up considerably - which shows some inconsistencies.
...I sorted them by source worksheet and then by source column, and grouped them together, also pasting into columns instead of single cells.
Edit:
There's a number of "weird things" going on here that require some explanation so I know whether they're designed this way intentionally.
**See my "'<<<<<<" notes below (There are some specific questions, starting with *what happens if you don't disable screen updating, and don't ignore the errors with On Error Resume Next...?
Option Explicit
Private Sub cmd_button1_Click()
Dim WS1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet, ws4 As Worksheet
Set WS1 = Sheets("Sheet2")
Set ws2 = Sheets("Distribution")
Set ws3 = Sheets("Sheet3")
Set ws4 = Sheets("Sheet4")
'Dim LastRow As Long
Dim R As Long, LR As Long, n As Long, i As Integer
' <<<<< always ALLOW screen updating during troubleshooting, until your code
' <<<<< is functioning perfectly: It may give a clue to the problem.
'Application.ScreenUpdating = False
'Getting the row number of last cell '<<<<< variable [LastRow] is not being used.
'LastRow = ws2.Range("A" & Rows.Count).End(xlUp).Row
'Deleting any previous data from destination sheet
'ws2.Range("A2:AX10000").ClearContents
ws2.UsedRange.ClearContents ' <<<<<< instead of specifying a range, just clear what's used
For i = 1 To 10
'If value in V column of the row is "" then copy the row to destination sheet
If WS1.Cells(i, "V").Value = "" Then
WS1.Range("A:A").Copy Destination:=ws2.Range("E:E") '<<< there's no pattern to what's being copied,
WS1.Range("E:G").Copy Destination:=ws2.Range("A:C") '<<< (and in a strange criss-cross),
WS1.Range("O:S").Copy Destination:=ws2.Range("F:I") '<<< are you sure nothing's being missed?
WS1.Range("T:T").Copy Destination:=ws2.Range("K:K")
ws3.Range("A:A").Copy Destination:=ws2.Range("O:O")
ws3.Range("E:G").Copy Destination:=ws2.Range("L:N")
ws3.Range("S:T").Copy Destination:=ws2.Range("P:Q")
ws3.Range("V:X").Copy Destination:=ws2.Range("R:T")
ws4.Range("A:A").Copy Destination:=ws2.Range("X1")
ws4.Range("F:H").Copy Destination:=ws2.Range("U:W")
ws4.Range("L:Q").Copy Destination:=ws2.Range("Y:AD")
End If
Next i
LR = Cells(Rows.Count, "C").End(xlUp).Row
Range("A2:AX" & LR).Sort Key1:=Range("A2"), Order1:=xlAscending '<<<<< this could be a problem??
For R = 2 To LR
'Count the number of duplicates for third row
n = Application.CountIf(Columns(3), Cells(R, 3).Value)
'Sum up the values for every duplicate
Range("F" & R).Value = Evaluate("=Sum(F" & R & ":F" & R + n - 1 & ")") '<<<<<< this is a strange way to do this...,
Range("G" & R).Value = Evaluate("=Sum(G" & R & ":G" & R + n - 1 & ")") '<<<<<< can you explain the purpose of these lines?
Range("H" & R).Value = Evaluate("=Sum(H" & R & ":H" & R + n - 1 & ")") '<<<<<< why not just add the cells normally instead like this?
Range("I" & R).Value = Evaluate("=Sum(I" & R & ":I" & R + n - 1 & ")")
Range("J" & R).Value = Evaluate("=Sum(J" & R & ":J" & R + n - 1 & ")")
Range("K" & R).Value = Evaluate("=Sum(K" & R & ":K" & R + n - 1 & ")")
Range("E" & R).Value = Evaluate("=Count(E" & R & ":E" & R + n - 1 & ")")
'Go to next value in third column
R = R + n - 1 '<<<<< WOAH! don't change the value of R when it's being used inside a loop!!!
Next R
'On Error Resume Next '<<<<< Errors mean something - Don't ignore them! (especially during troubleshooting)
'Remove all duplicates
ws2.Range("$A$1:$K$7979").RemoveDuplicates Columns:=3, Header:=xlYes '<<< this shifts cells around, might be a problem
On Error GoTo 0
'Fill out the table with values
Columns("A:K").AutoFit
Application.ScreenUpdating = True
Range("A1").Select
End Sub

Related

How would I express Last Row + 10?

I have a code that counts the rows in column A and then runs this array formula in the corresponding rows in other columns, I am wondering if it's possible to have the code run +10 more times than the last row.
For example if there are only populated fields in Column A2 and A3, I would like this code to run 12 times from J2-J14 so it takes the last row +10 if this is possible?
Thank you in advance :)
Dim i As Integer
Dim lastRow As Integer
lastRow = Range("A" & Rows.count).End(xlUp).Row
For i = 1 To lastRow
Range("J" & i + 1).FormulaArray = "=IFERROR(INDEX('Z:\Customer Operations\[O.xlsx]S'!$A:$A, SMALL(IF(A2='Z:\Customer Operations\[O.xlsx]S'!$K:$K, ROW('Z:\Customer Operations\[O.xlsx]S'!$A:$A)-MIN(ROW('Z:\Customer Operations\[O.xlsx]S'!$A:$A))+1, """"), ROW(A" & i & "))),"""")"
Range("K" & i + 1).FormulaArray = "=IFERROR(INDEX('Z:\Customer Operations\[O.xlsx]S'!$D:$D, SMALL(IF(A2='Z:\Customer Operations\[O.xlsx]S'!$K:$K, ROW('Z:\Customer Operations\[O.xlsx]S'!$D:$D)-MIN(ROW('Z:\Customer Operations\[O.xlsx]S'!$D:$D))+1, """"), ROW(A" & i & "))),"""")"
Next i
For i = 2 To 50
Range("L" & i).Formula = "=IF(J" & i & "="""","""",SUMIFS(E:E,D:D,J" & i & "))"
Next
Try,
Dim LastRow As Integer
'// ADD 10 to lastrow
LastRow = Range("A" & Rows.Count).End(xlUp).Row + 10
'// formulas
Range("J2:J" & LastRow).FormulaArray = "=IFERROR(INDEX('Z:\Customer Operations\[O.xlsx]S'!$A:$A, SMALL(IF(A2='Z:\Customer Operations\[O.xlsx]S'!$K:$K, ROW('Z:\Customer Operations\[O.xlsx]S'!$A:$A)-MIN(ROW('Z:\Customer Operations\[O.xlsx]S'!$A:$A))+1, """"), ROW(A2))),"""")"
Range("K2:K" & LastRow).FormulaArray = "=IFERROR(INDEX('Z:\Customer Operations\[O.xlsx]S'!$D:$D, SMALL(IF(A2='Z:\Customer Operations\[O.xlsx]S'!$K:$K, ROW('Z:\Customer Operations\[O.xlsx]S'!$A:$A)-MIN(ROW('Z:\Customer Operations\[O.xlsx]S'!$A:$A))+1, """"), ROW(A2))),"""")"
'// formulas
Range("L2:L50").Formula = "=IF(J2="""","""",SUMIFS(E:E,D:D,J2))"
If A2 is fixed then use $A$2 for small function

Check if value is in array then do

I have the following data:
The problem I'm trying to solve is that sometimes the Column H (Place) and Column I (Country) switch places (ex: lines 9,10,11). What I would like to do is:
First check if the year is within the last 3 years (I don't need to fix data older than that).
Load a range of values into an array.
Compare if the values in Column H are in the array.
If not, then switch values between columns. I did that by simply copying and pasting.
I'm stuck at this point. Sorry if it's ugly, first time dealing with arrays
The list I load into the array is in one workbook and the data is on another workbook. Does it work or they need to be on the same workbook?
Sub check_data()
Sheets("list").Activate 'this workbook
Dim DirArray As Variant
DirArray = Range("a1:a18").Value 'loads the range into an array
mypath = "//mynetworkpath/" 'sets the path
file = Dir(mypath & "filename.csv") 'indicates name of the file
Workbooks.Open (mypath & file) 'opens the file
Dim lastrow As Long
lastrow = Cells(Rows.Count, 2).End(xlUp).Row 'sorting by year
Range("A2:K" & lastrow).Sort key1:=Range("B2:B" & lastrow), _
order1:=xlDescending, Header:=xlNo
end_year = Format(Now, "yyyy") - 3 ' last 3 years
x = 2 'starts from second row
Do Until Cells(x, 2) = end_year 'cells(row,col)
For y = LBound(DirArray) To UBound(DirArray)
If Sheet1.Cells(x, 8) = DirArray(y) Then
Range("H" & x).Select
Selection.Copy
Range("M" & x).Select
ActiveSheet.Paste
Range("I" & x).Select
Application.CutCopyMode = False
Selection.Copy
Range("H" & x).Select
ActiveSheet.Paste
Range("M" & x).Select
Application.CutCopyMode = False
Selection.Copy
Range("I" & x).Select
ActiveSheet.Paste
Exit For
End If
Next
x = x + 1
Loop
ActiveWorkbook.Save
ActiveWorkbook.Close True
End Sub
Any guidance is helpful!
Thanks
You can leave the list on the worksheet and use match to check the values:
Sub check_data()
Const FPATH As String = "\\mynetworkpath\" 'use Const for fixed values
Dim rngVals As Range, wb As Workbook, lastrow As Long
Dim ws As Worksheet, tmp, file
Set rngVals = ThisWorkbook.Sheets("list").Range("a1:a18") 'your lookup list
file = Dir(FPATH & "filename.csv")
If Len(file) > 0 Then
Set wb = Workbooks.Open(FPATH & file) 'opens the file
Set ws = wb.Worksheets(1)
lastrow = ws.Cells(ws.Rows.Count, 2).End(xlUp).Row
ws.Range("A2:K" & lastrow).Sort key1:=ws.Range("B2:B" & lastrow), _
order1:=xlDescending, Header:=xlNo
end_year = Year(Now) - 3 ' last 3 years
x = 2 'starts from second row
Do Until Cells(x, 2) = end_year 'cells(row,col)
tmp = ws.Cells(x, 8).Value
'use Match to check the value against the list
m = Application.Match(tmp, rngVals, 0)
If Not IsError(m) Then
'got a match, so swap the values from H and I
ws.Cells(x, 8).Value = ws.Cells(x, 9).Value
ws.Cells(x, 9).Value = tmp
End If
x = x + 1
Loop
wb.Save
wb.Close
End If 'got the file
End Sub

Comparing a value between two arrays and passing back

I have two tables that have an identical column structure where the information passed from a different department is put into the first template.
I want to look at the SKU from Table 1 and pass back everything that matches on that row in Table 2 - whilst ignoring any SKU code that is not on Table 1.
Graphical illustration of problem
The code is part of a larger sub (variables are declared prior etc.) which uses a scripting dictionary and then goes through a For loop - but this is not efficient:
Set dlCD1 = CreateObject("Scripting.Dictionary")
Row = 1
On Error GoTo Error
For Each cCD1 In Sheets("TABLE 2 SHEET").Range("c1:c" & MaxLineMPS)
tmpCD1 = Trim(cCD1.Value)
If Len(tmpCD1) < 10 Then tmpCD1 = "0" & tmpCD1
If Len(tmpCD1) > 0 Then dlCD1(tmpCD1) = dlCD1(tmpCD1) + 1
Next cCD1
For Each kCD1 In dlCD1.keys
With Sheets("TABLE 1 SHEET").Range("a2:x" & MaxLineMatrice)
.AutoFilter Field:=3, Criteria1:=kCD1
End With
If Sheets("TABLE 1 SHEET").Range("A2:A" & MaxLineMatrice).SpecialCells(xlCellTypeVisible).Count > 1 Then
With Sheets("TABLE 1 SHEET").Range("d$3:x" & "$" & MaxLineMatrice).SpecialCells(xlCellTypeVisible)
.Value = Sheets("TABLE 2 SHEET").Range("$d" & "$" & Row & ":$x" & "$" & Row).Value
End With
Else: End If
Row = Row + 1
Debug.Print kCD1, dlCD1(kCD1)
Next kCD1
Worksheets("TABLE 1 SHEET").AutoFilterMode = False
dlCD1.RemoveAll
I have thousands of SKU codes and this takes time to loop through. I am told that by doing this outside of the sheet I can do the job faster.
Here's my whole code:
Sub Month_RiempiFuturo()
Dim MinLineMatrice As Integer, MaxLineMatrice As Integer, MinLineMPS As Integer, MaxLineMPS As Integer, row As Integer
Dim dlCD1 As Object, cCD1 As Range, kCD1, tmpCD1 As String, dlCD2 As Object, cCD2 As Range, kCD2, tmpCD2 As String
Dim StartTime As Double, SecondsElapsed As Double
Dim PT1 As PivotTable
Application.EnableEvents = False
Application.DisplayStatusBar = False
Application.ScreenUpdating = False
ActiveSheet.DisplayPageBreaks = False
Application.Calculation = xlCalculationManual
Worksheets("TABLE SHEET 1").AutoFilterMode = False
Worksheets("TABLE SHEET 2").AutoFilterMode = False
StartTime = Timer
MinLineMatrice = 3
MaxLineMatrice = Sheets("TABLE SHEET 1").Range("A" & Rows.Count).End(xlUp).Row
MinLineMPS = 1
MaxLineMPS = Sheets("TABLE SHEET 2").Range("C" & Rows.Count).End(xlUp).Row
LastLineFINITY = Sheets("FINITY CAPACITY PLANNED").Range("A" & Rows.Count).End(xlUp).Row
Set PT1 = Worksheets("shift").PivotTables("Tabella_pivot1")
Worksheets("TABLE SHEET 1").Range("d3:x" & MaxLineMatrice).ClearContents
Set dlCD1 = CreateObject("Scripting.Dictionary")
Row = 1
On Error GoTo Error
For Each cCD1 In Sheets("TABLE SHEET 2").Range("c1:c" & MaxLineMPS)
tmpCD1 = Trim(cCD1.Value)
If Len(tmpCD1) < 10 Then tmpCD1 = "0" & tmpCD1
If Len(tmpCD1) > 0 Then dlCD1(tmpCD1) = dlCD1(tmpCD1) + 1
Next cCD1
For Each kCD1 In dlCD1.keys
With Worksheets("TABLE SHEET 1").Range("a2:x" & MaxLineMatrice)
.AutoFilter Field:=3, Criteria1:=kCD1
End With
If Sheets("TABLE SHEET 1").Range("A2:A" & MaxLineMatrice).SpecialCells(xlCellTypeVisible).Count > 1 Then
With Sheets("TABLE SHEET 1").Range("d$3:x" & "$" & MaxLineMatrice).SpecialCells(xlCellTypeVisible)
.Value = Sheets("TABLE SHEET 2").Range("$d" & "$" & Row & ":$x" & "$" & Row).Value
End With
Else: End If
Row = Row + 1
Debug.Print kCD1, dlCD1(kCD1)
Next kCD1
Worksheets("TABLE SHEET 1").AutoFilterMode = False
dlCD1.RemoveAll
Set dlCD1 = CreateObject("Scripting.Dictionary")
For Each cCD1 In Sheets("Finity capacity planned").Range("a2:a" & LastLineFINITY)
tmpCD1 = Trim(cCD1.Value)
If Len(tmpCD1) > 0 Then dlCD1(tmpCD1) = dlCD1(tmpCD1) + 1
Next cCD1
Set dlCD2 = CreateObject("Scripting.Dictionary")
For Each cCD2 In Sheets("Finity capacity planned").Range("b2:b" & LastLineFINITY)
tmpCD2 = Trim(cCD2.Value)
If Len(tmpCD2) > 0 Then dlCD2(tmpCD2) = dlCD2(tmpCD2) + 1
Next cCD2
For Each kCD1 In dlCD1.keys
With Sheets("Finity capacity planned").Range("A1:Ak" & LastLineFINITY)
.AutoFilter Field:=1, Criteria1:=kCD1
.AutoFilter Field:=2, Criteria1:=Array( _
dlCD2.keys()(0), dlCD2.keys()(2), dlCD2.keys()(4), dlCD2.keys()(6), dlCD2.keys()(8), dlCD2.keys()(10)), Operator:=xlFilterValues
End With
With Sheets("Finity capacity planned").Range("A2:Ak" & LastLineFINITY).SpecialCells(xlCellTypeVisible)
.Interior.ColorIndex = 15
End With
With Sheets("Finity capacity planned").Range("A1:Ak" & LastLineFINITY)
.AutoFilter Field:=1, Criteria1:=kCD1
.AutoFilter Field:=2, Criteria1:=Array( _
dlCD2.keys()(1), dlCD2.keys()(3), dlCD2.keys()(5), dlCD2.keys()(7), dlCD2.keys()(9), dlCD2.keys()(11)), Operator:=xlFilterValues
End With
With Sheets("Finity capacity planned").Range("A2:Ak" & LastLineFINITY).SpecialCells(xlCellTypeVisible)
.Interior.ColorIndex = 19
End With
Debug.Print kCD1, dlCD1(kCD1)
Next kCD1
Worksheets("Finity capacity planned").AutoFilterMode = False
dlCD1.RemoveAll
dlCD2.RemoveAll
With PT1
.RefreshTable
End With
Application.EnableEvents = True
Application.DisplayStatusBar = True
Application.ScreenUpdating = True
ActiveSheet.DisplayPageBreaks = True
Application.Calculation = xlCalculationAutomatic
SecondsElapsed = Round(Timer - StartTime, 2)
MsgBox "This code including the time for user prompts to be acknowledged took " & SecondsElapsed & " Seconds", vbInformation, "McManus automation speed testing"
Exit Sub
Error:
Application.EnableEvents = True
Application.DisplayStatusBar = True
Application.ScreenUpdating = True
ActiveSheet.DisplayPageBreaks = True
Application.Calculation = xlCalculationAutomatic
MsgBox "Something went wrong"
End Sub
You can use Find function to find the row number you are looking for. Then using this row number, you can have the data from that row.
I didn't dig into your code too much, because it is a bit messy. So considering that:
Blank Lookup sheet name is "TABLE 1 SHEET",
Master Lookup sheet name is "TABLE 2 SHEET",
Results sheet name is "TABLE 3 SHEET",
then you can try the following:
Sub findmydata()
Dim ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet
Dim i As Long, j As Long, foundrow As Long, lastrow1 As Long, lastrow2 As Long
Set ws1 = Sheets("TABLE 1 SHEET")
Set ws2 = Sheets("TABLE 2 SHEET")
Set ws3 = Sheets("TABLE 3 SHEET")
lastrow1 = ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row
lastrow2 = ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row
For i = 1 To lastrow1
On Error Resume Next
foundrow = ws2.Range("A1:A" & lastrow2).Find(ws1.Cells(i, 1).Value).Row
If Err.Number = 91 Then
ws3.Cells(i, 1) = ws1.Cells(i, 1)
Else
For j = 1 To 4
ws3.Cells(i, j) = ws2.Cells(foundrow, j)
Next j
End If
Next
End Sub

Transposing an Array and Autofilling

I'm looking for a more efficient, less hard-coded way of transposing an array and then autofilling formulas in adjacent columns. Here is my current code for transposing my array in a specific spot on the sheet and autofilling the columns:
If Len(Join(myArray)) > 0 Then
ActiveWorkbook.Sheets("Delta Summary").Range("A3:A" & UBound(myArray) + 2) = WorksheetFunction.Transpose(myArray)
ActiveWorkbook.Sheets("Delta Summary").Range("B3").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.AutoFill Destination:=Range("B3:K17"), Type:=xlFillDefault
Else: End If
The goal is to transpose the array starting in cell A3 on sheet "Delta Summary". My code accomplishes this, but I'm wondering if there's a better way to do it. For reference, I loop through this array and transpose it several times based on different criteria. I transpose the array beginning at cells A3, A20, A37,..., and A224. Each section has 15 cells allocated for data.
As for the auto-fill, I'd like to auto-fill the formulas in columns B:K down to the last populated cell in column A for that pre-defined range (ex. A3:A17, A20:34, etc.). I don't know how to find the last populated cell for a pre-defined range, so I have this hardcoded.
I'm still learning, so any insight would be greatly appreciated!
Edit: Here is one example of the looping criteria I use to populate my array:
ReDim myArray(0)
For i = 1 To LastCurrID
If ActiveWorkbook.Sheets("Weekly Comparison").Range("N" & i) = "N" And ActiveWorkbook.Sheets("Weekly Comparison").Range("J" & i) = "Billing" Then
myArray(UBound(myArray)) = ActiveWorkbook.Sheets("Weekly Comparison").Range("A" & i)
ReDim Preserve myArray(UBound(myArray) + 1)
End If
Next i
Edit #2: For those who are curious, here's the completed code. I only slightly changed what was commented below.
ReDim myArray(0)
For i = 1 To LastCurrID
If wkb.Sheets("Weekly Comparison").Range("N" & i) = "N" And wkb.Sheets("Weekly Comparison").Range("J" & i) = "Billing" Then
myArray(UBound(myArray)) = wkb.Sheets("Weekly Comparison").Range("A" & i)
ReDim Preserve myArray(UBound(myArray) + 1)
End If
Next i
For y = LBound(myArray) To UBound(myArray)
If Len(Join(myArray)) > 0 Then
With wks
.Range("A" & x & ":A" & UBound(myArray) + x - 1) = WorksheetFunction.Transpose(myArray)
Dim lRow As Long
lRow = .Range("A" & x).End(xlDown).Row - x + 1
.Range("B" & x).Resize(1, 10).AutoFill _
Destination:=.Range("B" & x).Resize(lRow, 10), Type:=xlFillDefault
End With
End If
Next
x = x + 17
EDIT (Based on OP Update Question with Looping)
From the way you build your array, it seems like the array is loading with the last row of the data range to be copied (within the 15 row limit) for each range.
The below will loop through the array again, and will set a factor of 17 to x for each loop (starting at 3) and will find the last row within the specified range starting at 'Bx' and uses the .Resize method to do the AutoFill:
'always best to qualify the workbook, worksheet objects with a variable
Dim wkb As Workbook, wks As Worksheet
Set wkb = Workbooks("myWKb")
Set wks = wkb.Sheets("Delta Summary")
Dim x As Long, y As Long
x = 3
For y = LBound(myArray) To UBound(myArray)
If Len(Join(myArray)) > 0 Then
With wks
.Range("A" & x & ":A" & UBound(myArray) + 2) = WorksheetFunction.Transpose(myArray)
Dim lRow As Long
lRow = .Range("A" & x).End(xlDown).Row
.Range("B" & x).Resize(1, 10).AutoFill _
Destination:=.Range("B" & x).Resize(lRow, 10), Type:=xlFillDefault
End With
End If
x = x + 17
Next

VBA code takes very long time to execute

The following VBA code takes very long time to execute. I ran it 25 minutes ago for 48,000 rows and it's still running. How can I shorten the execution time?
Sub delrows()
Dim r, RowCount As Long
r = 2
ActiveSheet.Columns(1).Select
RowCount = UsedRange.Rows.Count
userresponse = MsgBox("You have " & RowCount & " rows", vbOKOnly, "Info")
Rows(RowCount).Delete Shift:=xlUp
' Trim spaces
Columns("A:A").Select
Selection.Replace What:=" ", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, searchFormat:=False, _
ReplaceFormat:=False
' Delete surplus columns
Range("L:T,V:AA,AE:AG,AR:AR,AU:AU,AZ:AZ").Select
Selection.Delete Shift:=xlToLeft
' Delete surplus rows
Do
If Left(Cells(r, 1), 1) = "D" _
Or Left(Cells(r, 1), 1) = "H" _
Or Left(Cells(r, 1), 1) = "I" _
Or Left(Cells(r, 1), 2) = "MD" _
Or Left(Cells(r, 1), 2) = "ND" _
Or Left(Cells(r, 1), 3) = "MSF" _
Or Left(Cells(r, 1), 5) = "MSGZZ" _
Or Len(Cells(r, 1)) = 5 _
Or Cells(r, 3) = 0 Then
Rows(r).Delete Shift:=xlUp
ElseIf Int(Right(Cells(r, 1), 4)) > 4000 Then
Rows(r).Delete Shift:=xlUp
Else: r = r + 1
End If
Loop Until (r = RowCount)
End Sub
The biggest issue is probably the amount of data you are looping through. I've updated your code to create a formula to check if the row needs to be deleted, then you can filter on that formula result and delete all rows at once.
I've made a bunch of comments to both help you clean your code and understand what I did. I prefaced my comments with '=>.
One last note, loading the values into an array may help as well, but if you have many, many columns of data, this may be more difficult. I don't have a ton of experience with it, but I know it makes things worlds faster!
Good luck and have fun!
Option Explicit
Sub delrows()
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
Dim r As Long, RowCount As Long
r = 2
Dim wks As Worksheet
Set wks = Sheets(1) '=> change to whatever sheet index (or name) you want
'=> rarely a need to select anything in VBA [ActiveSheet.Columns(1).Select]
With wks
RowCount = .Range("A" & .Rows.Count).End(xlUp).Row '=> as opposed to [RowCount = UsedRange.Rows.Count], as UsedRange can be misleading
'NOTE: this also assumes Col A will have your last data row, can move to another column
userresponse = MsgBox("You have " & RowCount & " rows", vbOKOnly, "Info")
.Rows(RowCount).Delete Shift:=xlUp
' Trim spaces
'=> rarely a need to select anything in VBA [Columns("A:A").Select]
.Range("A1:A" & RowCount).Replace What:=" ", Replacement:="", lookat:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, searchFormat:=False, _
ReplaceFormat:=False
' Delete surplus columns
'=> rarely a need to select anything in VBA [Range("L:T,V:AA,AE:AG,AR:AR,AU:AU,AZ:AZ").Select]
.Range("L:T,V:AA,AE:AG,AR:AR,AU:AU,AZ:AZ").Delete Shift:=xlToLeft ' as opposed to Selection.Delete Shift:=xlToLeft
' Delete surplus rows
'=> Now, here is where we help you loop:
'=> First insert column to the right to capture your data
.Columns(1).Insert Shift:=xlToRight
.Range("A1:A" & RowCount).FormulaR1C1 = "=If(OR(Left(RC[1],1) = ""D"",Left(RC[1],1) = ""H"", Left(RC[1],1) = ""I"", Left(RC[1],2) = ""MD"",Left(RC[1],2) = ""ND"",Left(RC[1],3) = ""MSF"",Left(RC[1],5) = ""MSGZZ"",Len(RC[1])=5),""DELETE"",If(Int(Right(RC[1],4)) > 4000,""DELETE"",""""),""""))"
'=> Now, assuming you something to delete ...
If Not .Columns(1).Find("DELETE", LookIn:=xlValues, lookat:=xlWhole) Is Nothing Then
'=> filter and delete
.Range("A1:A" & RowCount).AutoFilter 1, "DELETE"
Intersect(.UsedRange, .UsedRange.Offset(1), .Range("A1:A" & RowCount)).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End If
'=> Get rid of formula column
.Columns(1).EntireColumn.Delete
End With
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End Sub
the reason its so slow is you are iterating over each cell. Below copies to an array, finds the rows that need deleting and then deletes. Update Sheet4 to your sheet and Range("A2").CurrentRegion to the area you require:
Dim data() As Variant
Dim count As Double, i As Double, z As Double, arrayCount As Double
Dim deleteRowsFinal As Range
Dim deleteRows() As Double
Application.ScreenUpdating = False
data = Sheet4.Range("A2").CurrentRegion.Value2
For i = 1 To UBound(data, 1)
count = count + 1
If (data(i, 1) = "D" Or Left(data(i, 1), 1) = "H" Or Left(data(i, 1), 1) = "I" Or Left(data(i, 1), 2) = "MD" _
Or Left(data(i, 1), 2) = "ND" Or Left(data(i, 1), 3) = "MSF" Or Left(data(i, 1), 5) = "MSGZZ" _
Or Len(data(i, 1)) = 5 Or data(i, 3) = 0 Or Int(Right(IIf(Cells(i, 1) = vbNullString, 0, Cells(i, 1)), 4)) > 4000) Then
ReDim Preserve deleteRows(arrayCount)
deleteRows(UBound(deleteRows)) = count
arrayCount = arrayCount + 1
End If
Next i
Set deleteRowsFinal = Sheet4.Rows(deleteRows(0))
For z = 1 To UBound(deleteRows)
Set deleteRowsFinal = Union(deleteRowsFinal, Sheet4.Rows(deleteRows(z)))
Next z
deleteRowsFinal.Delete Shift:=xlUp
Application.ScreenUpdating = True
Turn off the screen updates to start with. Add your observations post the following.
You can disable calculations as well, if you think it isn't affecting anything as such.
Application.ScreenUpdating = False
your code...
Application.ScreenUpdating = True
EDIT: I have uploaded a file here - https://dl.dropbox.com/u/24702181/TestDeleteRowsInChunk.xls
The workbook is macro enabled.
After opening, click on "Recover Data" followed by "Start Deleting".
Take a look at the code for details. I suppose it can be optimized further.
A couple of hints
Do a reverse loop.
Get cell contents in an array, use array to check for values.
Build a string for rows to be deleted.
Delete it in chunks.

Resources