Reputation: 107
I am working on an Excel VBA code for a spreadsheet. The aim of the following code is to count how many times the voucher number in this row appears in the whole column G. As the raw data has more than 60,000 rows, the following code will take more than 2 mins to finish.
Worksheets("Raw Data").Range("AP2:AP" & lastrow).Formula = "=IF(AO2=""MATCHED"",""MATCHED"",IF((COUNTIF(AQ_u,G2))>0,""MATCHED"",""NOT MATCHED""))"
I also tried an alternatvie way, which basically is also a CountIF function:
Dim cel, rng As Range
Set rng = Worksheets("Raw Data").Range("AQ2:AQ" & lastrow)
For Each cel In Worksheets("Raw Data").Range("AQ2:AQ" & lastrow)
If Application.WorksheetFunction.CountIf(rng, cel.Offset(0, -36).Value) > 0 Then
cel.Offset(0, -1).Value = 1
End If
Next cel
Both of the codes above take a long time to finish, so I am wondering whether there is a way to make the code more efficient? Many thanks.
Upvotes: 1
Views: 2595
Reputation: 10705
Try the code bellow (it uses an array and a dictionary)
For dictionaries late binding is slow:
CreateObject("Scripting.Dictionary")Early binding is fast: VBA Editor -> Tools -> References -> Add Microsoft Scripting Runtime
Option Explicit
Public Sub CountVouchers()
Const G As Long = 7 'col G
Const AQ As Long = 43 'col AQ
Dim ws As Worksheet: Dim i As Long: Dim d As Dictionary
Dim arr As Variant: Dim lr As Long: Dim t As Double
t = Timer: Set d = New Dictionary
Set ws = ThisWorkbook.Worksheets("Raw Data")
lr = ws.Cells(ws.Rows.Count, AQ).End(xlUp).Row
ws.Columns("AP").Clear
arr = ws.Range(ws.Cells(1, 1), ws.Cells(lr, AQ)) 'Range to Array
For i = 2 To lr
If Len(Trim(arr(i, AQ))) > 0 Then d(CStr(arr(i, AQ))) = 1
Next
For i = 2 To lr
If d.Exists(CStr(arr(i, G))) Then arr(i, AQ - 1) = 1 'Count
Next
ws.Range(ws.Cells(1, 1), ws.Cells(lr, AQ)) = arr 'Array back to Range
Debug.Print "Rows: " & Format(lr, "#,###") & ", Time: " & Format(Timer - t, ".000") & " sec"
'Rows: 100,001, Time: 1.773 sec
End Sub
If you want to see total number of occurrences for each voucher:
Public Sub CountVoucherOccurrences()
Const G As Long = 7
Const AQ As Long = 43
Dim ws As Worksheet: Dim i As Long: Dim d As Dictionary
Dim arr As Variant: Dim lr As Long: Dim t As Double
t = Timer: Set d = New Dictionary
Set ws = ThisWorkbook.Worksheets("Raw Data")
lr = ws.Cells(ws.Rows.Count, AQ).End(xlUp).Row
ws.Columns("AP").Clear
arr = ws.Range(ws.Cells(1, 1), ws.Cells(lr, AQ))
For i = 2 To lr
d(arr(i, AQ)) = IIf(Not d.Exists(arr(i, AQ)), 1, d(arr(i, AQ)) + 1)
Next
For i = 2 To lr
If d.Exists(arr(i, G)) Then arr(i, AQ - 1) = d(arr(i, AQ))
Next
ws.Range(ws.Cells(1, 1), ws.Cells(lr, AQ)) = arr
Debug.Print "Rows: " & Format(lr, "#,###") & ", Time: " & Format(Timer - t, ".000") & " sec"
'Rows: 100,001, Time: 1.781 sec
End Sub
Upvotes: 1