Add items to an array rather than replacing - arrays

I have some code which uses arrays to get data from one worksheet (Cost Data) and essentially copy it to another worksheet (Compare Tool) in a side-by-side, comparison format. I got everything to work only to find out that in some cases, there are multiple lines of data on the Cost Data worksheet which meet the criteria. When these lines of data are assigned to my outarr array, it overwrites what was in there rather than adding to it.
I tried using the ReDim Preserve; however, I'm still getting an error. Any suggestions?
Sub Compare_Projects_Arrays()
Dim Toolary As Variant, Data_ary As Variant, PrjTitle_ary As Variant, CurrentAry As Variant, outarr As Variant
Dim r As Long, nr As Long, x As Long, c As Long, CurrentCostCod As Long
Dim Cl As Range
Dim Project1 As String, Project2 As String, Project3 As String, Project4 As String, Project5 As String, Project6 As String, Project7 As String, Project8 As String
Application.ScreenUpdating = False
On Error Resume Next
Sheets("Compare Tool").ShowAllData
Sheets("Cost Data").ShowAllData
Sheets("Compare Tool").Range("Clear_Cells").SpecialCells(xlConstants).ClearContents
Sheets("Compare Tool").Range("AD15:AD16,AD19,AQ15:AD16,AQ19,BD15:BD16,BD19,BQ15:BQ16,BQ19,CD15:CD16, CD19,CQ15:CQ16, CQ19,DD15:DD16, DD19,DQ15:DQ16,DQ19").ClearContents
Sheets("Compare Tool").Range("X23:DW24").ClearContents
On Error GoTo 0
With Sheets("Setup Page")
Typology = .Range("L18")
Project1 = .Range("U11").Value
Project2 = .Range("U12").Value
Project3 = .Range("U13").Value
Project4 = .Range("U14").Value
Project5 = .Range("U15").Value
Project6 = .Range("U16").Value
Project7 = .Range("U17").Value
Project8 = .Range("U18").Value
End With
With Sheets("Compare Tool")
Set SearchRangeTool = .Range("E:E").Find(What:="Last Row")
LastRowTool = SearchRangeTool.Row
If Project1 <> "" Then
.Range("X23") = Project1
.Range("X24") = "Typology: " & Typology
End If
If Project2 <> "" Then
.Range("AK23") = Project2
.Range("AK24") = "Typology: " & Typology
End If
If Project3 <> "" Then
.Range("AX23") = Project3
.Range("AX24") = "Typology: " & Typology
End If
If Project4 <> "" Then
.Range("BK23") = Project4
.Range("BK24") = "Typology: " & Typology
End If
If Project5 <> "" Then
.Range("BX23") = Project5
.Range("BX24") = "Typology: " & Typology
End If
If Project6 <> "" Then
.Range("CK23") = Project6
.Range("CK24") = "Typology: " & Typology
End If
If Project7 <> "" Then
.Range("CX23") = Project7
.Range("CX24") = "Typology: " & Typology
End If
If Project8 <> "" Then
.Range("DK23") = Project8
.Range("DK24") = "Typology: " & Typology
End If
End With
'Put data into the arrarys (Toolary & Data_ary)
Data_ary = Sheets("Cost Data").Range("A1").CurrentRegion.Value2
With Sheets("Compare Tool")
Toolary = .Range("A28:DV" & .Range("U" & Rows.Count).End(xlUp).Row).Value2
End With
'Project 1
'Check if Project field is blank
If Sheets("Setup Page").Range("U11") = "" Then GoTo Project2
With Sheets("Cost Data")
FirstRowDB = .Range("A:A").Find(What:=Project1, LookIn:=xlValues, SearchDirection:=xlNext).Row 'xlNext starts from top
GSFPrj = .Cells(FirstRowDB, 13)
GSFTypology = .Cells(FirstRowDB, 18)
End With
'Copy the GSF area & Total Project cost and paste into the top of the "Compare Tool" tab
Sheets("Prj Info").Select
FindPrj = Application.Match(Project1, Range("A:A"), 0)
Total_Prj_Cost = Sheets("Prj Info").Cells(FindPrj, 16)
Sheets("Compare Tool").Range("AD19") = GSFTypology
Sheets("Compare Tool").Range("AD16") = GSFPrj
Sheets("Compare Tool").Range("AD15") = Total_Prj_Cost
lastrow = UBound(Toolary)
outarr = Worksheets("Compare Tool").Range("X28:AI" & lastrow)
'The following will put the formulas from the subtotals lines into the "toolfrom" array and then put it into the "outarr" array
With Sheets("Compare Tool")
toolfrom = .Range("X28:AI" & lastrow).formula
End With
For i = 1 To UBound(outarr, 1)
For j = 1 To UBound(outarr, 2)
If Left(toolfrom(i, j), 1) = "=" Then 'erroring out at i=1 and j=10
outarr(i, j) = toolfrom(i, j)
End If
Next j
Next i
For r = 1 To lastrow
If Toolary(r, 5) = "Single" Or Toolary(r, 5) = "T2 Head" Then
CurrentCostCode = Toolary(r, 21)
CurrentT0 = Toolary(r, 9)
ReDim Preserve outarr(r) 'This is where the error happens
For x = 2 To UBound(Data_ary)
If Data_ary(x, 1) = Project1 And Data_ary(x, 34) = CurrentCostCode And Data_ary(x, 22) = CurrentT0 And Data_ary(x, 17) = Typology Then
outarr(r, 1) = Data_ary(x, 37) 'This is where the data is getting overwritten
outarr(r, 2) = Data_ary(x, 38) 'This is where the data is getting overwritten
outarr(r, 3) = Data_ary(x, 39) 'This is where the data is getting overwritten
outarr(r, 4) = Data_ary(x, 40) 'This is where the data is getting overwritten
outarr(r, 5) = Data_ary(x, 41) 'This is where the data is getting overwritten
outarr(r, 6) = Data_ary(x, 42) 'This is where the data is getting overwritten
outarr(r, 7) = Data_ary(x, 43) 'This is where the data is getting overwritten
If Data_ary(x, 44) <> "" Then
outarr(r, 8) = Data_ary(x, 44) 'This is where the data is getting overwritten
outarr(r, 9) = Data_ary(x, 45) 'This is where the data is getting overwritten
End If
End If
Next x
End If
Next r
Worksheets("Compare Tool").Range("X28:AF" & lastrow) = outarr
'Project 2
Project2:
Application.ScreenUpdating = True
End Sub

Related

VBA Error: Compile error in hidden module

I have an Excel File which I've designed to simplify a process at my workplace (with our customers)
One of the macro's is matching data between two different tabs, performing some calculations, and highlighting cells pink where an error has been found to highlight this to the end user. Most of this is done inside an array for speed (there can be quite a large volume of data)
This macro as well as all the other macros on this workbook are working perfectly well on my PC as well as my colleagues.
However, upon sending this file to some of our customers - they have reported having an issue upon running the macro I mentioned above. They have shared the below message (link below):
'Compile Error in hidden module: .............
This error commonly occurs when code is incompatible with the version, platform, or architecture of this application.
I've read this probably has to do with 32 bit vs 64 bit versions of Windows and that I might need to alter my code to account for this. However, I'm not using any declare statements which call an API, and I'm also not using any Long variables which refer to Pointers or Handlers - so I'm a bit confused what might be causing this issue.
Please could somebody help me figure out what might be causing this error message on other PC's when the code works okay for me?
Sub RefreshData()
'Set Variables
Dim fd As Worksheet
Dim ld As Worksheet
Dim OrN As Worksheet
Dim RF As Worksheet
Set fd = ThisWorkbook.Sheets("Feeder Data")
Set ld = ThisWorkbook.Sheets("Live Data")
Set OrN = ThisWorkbook.Sheets("Order Numbers")
Set RF = ThisWorkbook.Sheets("reference")
Dim PeriodReturnRange As Range
Dim YearReturnRange As Range
Dim DateLookUpRange As Range
Set PeriodReturnRange = RF.Range("K3:K200")
Set YearReturnRange = RF.Range("I3:I200")
Set DateLookUpRange = RF.Range("J3:J200")
Dim fdArray() As String
Dim ldArray() As String
Dim OrNArray() As String
Dim ldArray2() As String
'' 1) Set the size of the Feeder Data Array
On Error GoTo ErrorMsgfd
ReDim Preserve fdArray(6 To fd.Range("C" & Rows.Count).End(xlUp).Row, 3 To 14)
On Error GoTo 0
'' 2) Set size of Live Data Array
On Error GoTo ErrorMsgld
ReDim Preserve ldArray(10 To ld.Range("B" & Rows.Count).End(xlUp).Row, 2 To 28)
On Error GoTo 0
'' 3) Set Size of Order Number Array
On Error GoTo ErrorMsgOrN
ReDim Preserve OrNArray(8 To OrN.Range("J" & Rows.Count).End(xlUp).Row, 8 To 10)
On Error GoTo 0
''4) Set size of second Order Number to get info needed for saving calculation
On Error GoTo ErrorMsgld
ReDim Preserve ldArray2(10 To ld.Range("B" & Rows.Count).End(xlUp).Row, 14 To 22)
On Error GoTo 0
On Error GoTo PasswordErrorMsg
ld.Unprotect "password1234"
fd.Unprotect "password1234"
On Error GoTo 0
With Application
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
End With
On Error Resume Next
ld.ShowAllData
fd.ShowAllData
On Error GoTo 0
''''Perform Worksheet Clearing and copy formatting down to row 5500
With ld
.Range("E4").Copy
.Range("B10:B5500").PasteSpecial xlPasteFormats
.Range("G10:G5500").PasteSpecial xlPasteFormats
.Range("J10:J5500").PasteSpecial xlPasteFormats
.Range("O10:P5500").PasteSpecial xlPasteFormats
.Range("S10:S5500").PasteSpecial xlPasteFormats
.Range("Z10:Z5500").PasteSpecial xlPasteFormats
.Range("AA10:AA5500").PasteSpecial xlPasteFormats
.Range("F4").Copy
.Range("C10:F5500").PasteSpecial xlPasteFormats
.Range("I10:I5500").PasteSpecial xlPasteFormats
.Range("K10:N5500").PasteSpecial xlPasteFormats
.Range("Q10:R5500").PasteSpecial xlPasteFormats
.Range("T10:V5500").PasteSpecial xlPasteFormats
.Range("AA10:AB5500").PasteSpecial xlPasteFormats
.Range("G4").Copy
.Range("H10:H5500").PasteSpecial xlPasteFormats
.Range("W10:Y5500").PasteSpecial xlPasteFormats
.Range("C10:F5500").ClearContents
.Range("I10:I5500").ClearContents
.Range("K10:N5500").ClearContents
.Range("Q10:R5500").ClearContents
.Range("T10:V5500").ClearContents
.Range("AA10:AB5500").ClearContents
End With
'''''''Populate Arrays
''4) Populate Feeder Data Array with the data
For A = 6 To fd.Range("C" & Rows.Count).End(xlUp).Row
For B = 3 To 14
fdArray(A, B) = Trim(fd.Cells(A, B))
Next B
Next A
''5) Populate Live Data Array
For A = 10 To ld.Range("B" & Rows.Count).End(xlUp).Row
For B = 2 To 28
ldArray(A, B) = Trim(ld.Cells(A, B))
Next B
Next A
'' 6) Populate Order Number Array
For A = 8 To OrN.Range("J" & Rows.Count).End(xlUp).Row
For B = 8 To 10
OrNArray(A, B) = Trim(OrN.Cells(A, B))
Next B
Next A
''''''''' Match the values between Live Data and Feeder Data arrays (still not transferring back to worksheet)
Dim LookUp1 As String
Dim LookUp2 As String
Dim LookUp3 As String
For A = 10 To UBound(ldArray)
LookUp1 = ldArray(A, 2)
LookUp2 = ldArray(A, 7)
On Error Resume Next
ldArray(A, 11) = Application.WorksheetFunction.Lookup(CLng(CDate(ld.Range("J" & A).Value)), DateLookUpRange, PeriodReturnRange)
ldArray(A, 22) = Application.WorksheetFunction.Lookup(CLng(CDate(ld.Range("J" & A).Value)), DateLookUpRange, YearReturnRange)
On Error GoTo 0
For B = 6 To UBound(fdArray)
If fdArray(B, 3) = LookUp1 And fdArray(B, 9) = LookUp2 Then
On Error Resume Next
''Calculation 1
If fd.Range("H" & B).Value = "ABC" Then
ldArray(A, 28) = fd.Range("N" & B).Value * (ld.Range("Z" & A).Value / 1000)
Else
ldArray(A, 28) = fd.Range("N" & B).Value * (ld.Range("Z" & A).Value / 100)
End If
''Calculation 2
ldArray(A, 17) = fd.Range("K" & B).Value - (ld.Range("O" & A).Value * fd.Range("L" & B).Value) - (ld.Range("P" & A).Value * fd.Range("M" & B).Value)
''Calculation 3
ldArray(A, 18) = (ld.Range("O" & A).Value * fd.Range("L" & B).Value) + (ld.Range("P" & A).Value * fd.Range("M" & B).Value)
On Error GoTo 0
''''''''Lookup results
'Result 1
ldArray(A, 3) = fdArray(B, 4)
'Result 2
ldArray(A, 4) = fdArray(B, 5)
'Result 3
ldArray(A, 5) = fdArray(B, 6)
'Result 4
ldArray(A, 6) = fdArray(B, 7)
'Result 5
ldArray(A, 9) = fdArray(B, 8)
'Result 6
ldArray(A, 13) = fdArray(B, 10)
'Result 7
ldArray(A, 14) = fdArray(B, 11)
'Result 8
ldArray(A, 20) = fdArray(B, 12)
'Result 9
ldArray(A, 21) = fdArray(B, 13)
'Result 10
ldArray(A, 27) = fdArray(B, 14)
Exit For
End If
Next B
''Check for blanks, highlight that there has been an error if found
If ldArray(A, 4) = "" Or ldArray(A, 5) = "" Then
ld.Range("B" & A).Interior.Color = RGB(253, 211, 211)
ld.Range("G" & A).Interior.Color = RGB(253, 211, 211)
End If
''Check for blanks, highlight that there has been an error if found
If ldArray(A, 11) = "" Or ldArray(A, 22) = "" Then
ld.Range("J" & A).Interior.Color = RGB(253, 211, 211)
End If
Next A
''''Run a second loop between live data and order numbers, to match relevant order numbers
For A = 10 To UBound(ldArray)
LookUp1 = ldArray(A, 7)
LookUp2 = ldArray(A, 5)
For C = 8 To UBound(OrNArray)
''check if a particular special value was found and return matched result to array if it was, and ignore second lookup value
If LookUp1 = "xxx" And OrNArray(C, 9) = "xxx" Then
ldArray(A, 12) = OrNArray(C, 10)
''IF special value not found, test against both lookup values''
Else
If OrNArray(C, 9) = LookUp1 And OrNArray(C, 8) = LookUp2 Then
ldArray(A, 12) = OrNArray(C, 10)
Exit For
End If
End If
Next C
If ldArray(A, 12) = "" Then
ld.Range("L" & A).Interior.Color = RGB(253, 211, 211)
End If
Next A
''7) Transfer the matched arrays to the Worksheet
ld.Range("B10", ActiveCell.Offset(UBound(ldArray, 1) - 10, UBound(ldArray, 2) - 23)).Value = ldArray
''''''''''Load second live data Array containing only relevant columns'''''''
For A = 10 To ld.Range("B" & Rows.Count).End(xlUp).Row
For B = 14 To 22
ldArray2(A, B) = ld.Cells(A, B)
Next B
Next A
''''''''''''Loop to check if a special condition has been met and color if needed'''''''''''''''''''''''''''''
For A = 10 To UBound(ldArray2)
With ld.Rows(A)
If ldArray2(A, 19) = "" And ldArray2(A, 14) = ldArray2(A, 17) And _
Application.CountIfs(ld.Range("D10:D" & A), .Columns("D").Value, ld.Range("V10:V" & A), .Columns("V").Value, ld.Range("K10:K" & A), .Columns("K").Value) > 1 Then
.Columns("S").Interior.Color = RGB(253, 211, 211)
End If
End With
Next A
Erase fdArray
Erase ldArray
Erase OrNArray
Erase ldArray2
'''reset formatting of columns correctly, and unlock editable columns
With ld
.Range("B10:B5500").Locked = False
.Range("G10:H5500").Locked = False
.Range("J10:J5500").Locked = False
.Range("W10:Z5500").Locked = False
.Range("S10:S5500").Locked = False
.Range("O10:P5500").Locked = False
.Range("L10:L10000").NumberFormat = "#"
.Range("E10:E10000").NumberFormat = "#"
.Range("Q10:Q10000").NumberFormat = "0.00"
.Range("Z10:AB10000").NumberFormat = "0.00"
End With
'''array is being sent as text - this line required to make data format correctly - not sure why!
ld.Range("B10:AB5500").Select
Selection.Value = Selection.Value
ld.Range("B10").Select
On Error GoTo PasswordErrorMsg
ld.Protect "password1234", AllowFiltering:=True
fd.Protect "password1234", AllowFiltering:=True
On Error GoTo 0
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = xlCalculationAutomatic
End With
Exit Sub
ErrorMsgfd:
MsgBox "No Data has been entered into the Feeder Data!", vbCritical, "Cannot Update"
Exit Sub
ErrorMsgld:
MsgBox "No Data has been entered into the Live Data!", vbCritical, "Cannot Update"
Exit Sub
ErrorMsgOrN:
MsgBox "No Data has been entered into the Order Numbers!", vbCritical, "Cannot Update"
Exit Sub
PasswordErrorMsg:
MsgBox "An incorrect password has been entered for this worksheet. Please change the password to the agreed text to continue!", vbCritical, "Incorrect Password!!"
End Sub

Removing duplicates in a for loop crashes Excel

I have a for next loop that runs through a couple hundred thousand lines making changes on most. Could an array to make this code run faster?
The example of my for loop. Sometimes it gets overloaded and crashes Excel. (FYI my loop has to run bottom to top for it to do its intended purpose.)
Sub RemoveDuplicates()
Dim shWorkBook As Worksheet
Dim wkb As Workbook
Dim FullYearData As Worksheet
Set wkb = ThisWorkbook
With wkb
Set shWorkBook = .Sheets("Workbook")
Set shFullYearData = .Sheets("FullYearData")
End With
Dim i As Long
Dim LastRowW As Long
On Error Resume Next
Call TurnOffCalc
FirstRowW = shWorkBook.Cells(1, 1).Row
FirstColW = shWorkBook.Cells(1, 1).Column
LastRowW = shWorkBook.Cells(Rows.Count, 1).End(xlUp).Row
LastColW = shWorkBook.Cells(2, Columns.Count).End(xlToLeft).Column
i = LastRowW
Sum = 0
shWorkBook.Activate
For i = LastRowW To 1 Step -1
If shWorkBook.Cells(i, 7) = shWorkBook.Cells(i - 1, 7) Then
shWorkBook.Cells(i, 26) = vbNullString
End If
If shWorkBook.Cells(i, 26).Value <> "" Then
shWorkBook.Cells(i, 27) = Sum + Cells(i, 25).Value
Sum = 0
ElseIf shWorkBook.Cells(i, 26).Value = "" Then
Sum = shWorkBook.Cells(i, 25).Value + Sum
End If
Next
p = FirstRowW + 1
For p = FirstRowW + 1 To LastRowW Step 1
shWorkBook.Cells(p, 28) = Application.WeekNum(shWorkBook.Cells(p, 3))
Next
shWorkBook.Cells(1, 28).Value = "Week Number"
Call TurnOnCalc
End Sub
Try something like this:
Sub RemoveDuplicates()
Dim shWorkBook As Worksheet
Dim wkb As Workbook
Dim FullYearData As Worksheet
Dim i As Long, Sum
Dim LastRowW As Long, LastColW As Long, tbl As Range, data
Set wkb = ThisWorkbook
With wkb
Set shWorkBook = .Sheets("Workbook")
'Set shFullYearData = .Sheets("FullYearData")
End With
LastRowW = shWorkBook.Cells(Rows.Count, 1).End(xlUp).Row
LastColW = shWorkBook.Cells(2, Columns.Count).End(xlToLeft).Column
Set tbl = shWorkBook.Range("A1").Resize(LastRowW, 28) 'include "Week number" (?)
data = tbl.Value 'get the range value as an array
data(1, 28) = "Week Number"
Sum = 0
For i = LastRowW To 1 Step -1
If data(i, 7) = data(i - 1, 7) Then data(i, 26) = vbNullString
If data(i, 26).Value <> "" Then
data(i, 27) = Sum + data(i, 25).Value
Sum = 0
Else
Sum = data(i, 25).Value + Sum
End If
If i > 1 Then data(i, 28) = CLng(Format(data(i, 3), "ww"))
Next
tbl.Value = data 'return the data
End Sub

Delete an item in an array

I have this code that browse all file types in VBA. It's already working but my what I want to do now is to delete the item in the array if it is one of the blocked file types.
Const exts = _
".ade.adp.app.asp.bas.bat.cer.chm.cmd.com.cpl.crt.csh.der.exe.fxp.gadget" & _
".hlp.hta.inf.ins.isp.its.js.jse.ksh.lnk.mad.maf.mag.mam.maq.mar.mas.mat" & _
".mau.mav.maw.mda.mdb.mde.mdt.mdw.mdz.msc.msh.msh1.msh2.mshxml.msh1xml" & _
".msh2xml.ade.adp.app.asp.bas.bat.cer.chm.cmd.com.cpl.crt.csh.der.exe.fxp" & _
".gadget.hlp.hta.msi.msp.mst.ops.pcd.pif.plg.prf.prg.pst.reg.scf.scr.sct" & _
".shb.shs.ps1.ps1xml.ps2.ps2xml.psc1.psc2.tmp.url.vb.vbe.vbs.vsmacros.vsw" & _
".ws.wsc.wsf.wsh.xnk."
file = Application.GetOpenFilename(MultiSelect:=True, Title:="Select the files you want to zip")
If IsArray(file) = True Then
'Create empty Zip File
ReDim Data(1 To UBound(file) + 1, 1 To 1)
efCount = Empty
' filter the list
For j = LBound(file) To UBound(file)
ext = LCase(Mid(file(j), InStrRev(file(j), ".")))
If InStr(1, exts, ext & ".") = 0 Then ' if not blacklisted
count = count + 1
Data(count, 1) = file(j)
Else
ReDim Preserve excludedFile(efCount)
excludedFile(efCount) = Dir(file(j))
efCount = efCount + 1
file(j - 1) = file(j) 'Ive tried this and other ways bu is not working
found = True
End If
Next
Thanks for the help.
you could go like this
Dim file As Variant
Dim efCount As Long, j As Long, count As Long
Dim ext As String
Dim found As Boolean
Const exts = _
".ade.adp.app.asp.bas.bat.cer.chm.cmd.com.cpl.crt.csh.der.exe.fxp.gadget" & _
".hlp.hta.inf.ins.isp.its.js.jse.ksh.lnk.mad.maf.mag.mam.maq.mar.mas.mat" & _
".mau.mav.maw.mda.mdb.mde.mdt.mdw.mdz.msc.msh.msh1.msh2.mshxml.msh1xml" & _
".msh2xml.ade.adp.app.asp.bas.bat.cer.chm.cmd.com.cpl.crt.csh.der.exe.fxp" & _
".gadget.hlp.hta.msi.msp.mst.ops.pcd.pif.plg.prf.prg.pst.reg.scf.scr.sct" & _
".shb.shs.ps1.ps1xml.ps2.ps2xml.psc1.psc2.tmp.url.vb.vbe.vbs.vsmacros.vsw" & _
".ws.wsc.wsf.wsh.xnk."
file = Application.GetOpenFilename(MultiSelect:=True, Title:="Select the files you want to zip")
If IsArray(file) = True Then
'Create empty Zip File
ReDim Data(1 To UBound(file))
ReDim excludedFile(1 To UBound(file))
efCount = 0
' filter the list
For j = LBound(file) To UBound(file)
ext = LCase(Mid(file(j), InStrRev(file(j), ".")))
If InStr(1, exts, ext & ".") = 0 Then ' if not blacklisted
count = count + 1
Data(count) = file(j)
Else
excludedFile(efCount + 1) = Dir(file(j))
efCount = efCount + 1
End If
Next
found = efCount > 0
End If
ReDim Preserve Data(1 To count)
ReDim Preserve excludedFile(1 To efCount)
file = Data
You can use function to delete particular value from array. Put this into your project:
Function DeleteElement(x As String, ByRef List() As String) ' As String
Dim i As Integer, el As Integer
Dim Result() As String
ReDim Result(UBound(List) - 1)
For i = 0 To UBound(List)
If x = List(i) Then
el = i
Exit For
End If
Next i
For i = 0 To UBound(Result)
If i < el Then
Result(i) = List(i)
Else
Result(i) = List(i + 1)
End If
Next i
DeleteElement = Result
End Function
You can use it like here:
Sub test2()
Dim arr1(3) As String
arr1(0) = "A"
arr1(1) = "B"
arr1(2) = "C"
arr1(3) = "D"
arr2 = DeleteElement("B", arr1)
End Sub

VBA Collections Increase Speed: Matching Two Lists, Find What Doesn't Match

I have to massive Excel sheets (rows 7500 and 16000). I need to see what items that are in list one are NOT in list two... and what items are in list two that are NOT in list one, and then paste those results on a third sheet.
I decided to store both lists in two Collections. So far that works well. When I try to loop through the Collections to find what doesn't match my computer freezes as the file is too big.
How can I change my code so that it is quicker? I feel like there must be a better way to do this instead of looping through every i in list one and every z in list two.
Thanks!
Sub FullListCompareFSvDF()
Worksheets("FundserveFL").Activate
'Open New Collection and define every variable
Dim FSTrades As New Collection
Dim c As Long
Dim i As Long
Dim z As Long
Dim searchFor As String
'enter the items into the list. There are blank rows and so the first IF Statement is to ignore these.
' The Else Statement shows an account number as the item and an account number & balance (FS.Offset(0,6).Value) as the key
Dim FS As Range
For Each FS In Sheet1.Range("L:L")
If FS = "" Then
Else: FSTrades.Add CStr(FS.Value & " " & FS.Offset(0, 6).Value)
End If
Next
Worksheets("DatafileFL").Activate
Dim DFTrades As New Collection
'enter the items into the list. There are blank rows as well as random numbers and so the first IF Statement is to ignore these (all account numbers are greater than 10000
'"Matching" is displayed for all errors - during an error read the account number from two columns over.
' The Else Statement shows an account number as the item and an account number & balance (FS.Offset(0,6).Value) as the key
Dim DF As Range
For Each DF In Sheet2.Range("H:H")
If DF = "" Or Not IsNumeric(DF.Offset(0, 2)) Or DF < 10000 Then
ElseIf DF.Offset(0, -4) = "MATCHING" Then
DFTrades.Add CStr(DF.Offset(0, 2).Value & " " & DF.Value)
Else:
DFTrades.Add CStr(DF.Value & " " & DF.Offset(0, -2).Value)
End If
Next
'loop through the first collection. Find the first item and try to match it with the items in the second collection.
'Collection 1 Item 1... is it in Collection 2 Item 1? No - then is it in Collection 2 Item 2? When a match is found, move on to Collection 1 Item 2... If no match is found send the item to "ForInvestigation" worksheet
For i = 1 To FSTrades.Count
searchFor = FSTrades(i)
z = 0
Do
z = z + 1
If z > DFTrades.Count Then
c = c + 1
Worksheets("ForInvestigation").Activate
Cells(c, 1).Value = DFTrades(i)
Exit Do
Else:
If DFTrades(z) = searchFor Then
Exit Do
End If
End If
Loop
Next
'Clear Collections
Set FSTrades = Nothing
Set DFTrades = Nothing
End Sub
Don't Activate
Read all the relevant cells into a variant array in one step. eg:
Dim V As Variant
With Worksheets("FundserveFL")
V = .Range("L1", .Cells(.Rows.Count, "L").End(xlUp)).Resize(columnsize:=6)
End With
Create a key for your collection that can be used to see if there is a duplicate.
On Error Resume Next
For i = 1 To UBound(V, 1)
If V(i, 1) <> "" Then
FSTrades.Add Item:=CStr(V(i, 1) & " " & V(i, 6)), Key:=CStr(V(i, 1) & " " & V(i, 6))
End If
Next i
On Error Resume Next
If you similarly handle the data on your second worksheet, creating an array, adding it to the same collection after creating a key which will "error" if you try to add a duplicate, you will wind up with a collection that contains no duplicates. Populate an array with that collection, and write it to your third worksheet.
I would guess that using the above technique will increase your speed by at least a factor of ten, if not more.
EDIT:
If you want to do something other than a unique list, it is merely a matter of understanding the logic. For example, if, as in your comment, you have two arrays 1,2,3,4 and 1,3,4,5, you could do something like the following. Understand, of course, that one assumption is that there are no duplicates within either array: (If there are, that can be handled also, would just require a different logic)
Sub foo()
Dim V1, V2
Dim COL As Collection
Dim I As Long
V1 = Array(1, 2, 3, 4)
V2 = Array(1, 3, 4, 5)
Set COL = New Collection
For I = 0 To UBound(V1)
COL.Add V1(I), CStr(V1(I))
Next I
On Error Resume Next
For I = 0 To UBound(V2)
COL.Add V2(I), CStr(V2(I))
Select Case Err.Number
Case 457 'This is a duplicate, so will remove
Err.Clear
COL.Remove CStr(V2(I))
Case Is <> 0
MsgBox "Error No. " & Err.Number & vbTab & Err.Description
End Select
Next I
Stop
End Sub
When the routine stops, if you examine COL you will see it only contains 2 and 5
I have a similarly sized list of stuff, and I frequently need to create a unique list of values. I'm not sure why you want to work with two collections at once though. It is much simpler to load the data from one sheet into the collection, then loop through the other sheet to see if it already exists in the collection. Here's some of my code to help you write yours.
Dim colUniqueSNs As New Collection
On Error Resume Next
For r = 2 To Sheets("Inventory").UsedRange.Rows.Count
strSN = Sheets("Inventory").Cells(r, 6).Text
strHost = Sheets("Inventory").Cells(r, 2).Text
If Not InCollection(colUniqueSNs, strSN) Then colUniqueSNs.Add strHost, strSN
Next
On Error GoTo 0
Public Function InCollection(col As Collection, key As Variant) As Boolean
Dim obj As Variant
On Error GoTo err
InCollection = True
obj = col(key)
Exit Function
err:
InCollection = False
End Function
You are starting with ranges and you are ending with them. How about skipping the Collections at all?
Pls try this:
Sub FullListCompareFSvDF()
Dim Ran1Val As Variant, Ran1ValOffset As Variant, Ran2Val As Variant
Ran1Val = Intersect(Sheet1.Columns(12), Sheet1.UsedRange).Value
Ran2Val = Intersect(Sheet1.Columns(18), Sheet1.UsedRange).Value
Dim i As Long, j As Long
For i = 1 To UBound(ranval1)
If Len(Ran1Val(i, 1)) Then Ran1Val(i, 1) = Ran1Val(i, 1) & " " & Ran2Val(i, 1)
Next
Ran2Val = Intersect(Sheet2.Range("D:J"), Sheet2.UsedRange).Value
Dim OutputVal() As Variant
ReDim OutputVal(1 To UBound(Ran1Val) + UBound(Ran2Val), 1 To 1)
For i = 1 To UBound(Ran2Val)
If Ran2Val(i, 5) <> "" And IsNumeric(Ran2Val(i, 7)) And Ran2Val(i, 5) > 10000 Then
If Ran2Val(i, 1) = "MATCHING" Then
Ran2Val(i, 1) = CStr(Ran2Val(i, 7) & " " & Ran2Val(i, 5))
Else
Ran2Val(i, 1) = CStr(Ran2Val(i, 5) & " " & Ran2Val(i, 3))
End If
If IsNumeric(Application.Match(Ran2Val(i, 1), Ran1Val, 0)) Then
j = j + 1
OutputVal(j, 1) = Ran2Val(i, 1)
End If
Else
Ran2Val(i, 1) = ""
End If
Next
ReDim Preserve Ran2Val(1 To UBound(Ran2Val), 1 To 1)
Dim runNer As Variant
For Each runNer In Ran1Val
If Len(runNer) Then
If IsNumeric(Application.Match(runNer, Ran2Val, 0)) Then
j = j + 1
OutputVal(j, 1) = runNer
End If
End If
Next
If j > 0 Then
Worksheets("ForInvestigation").Range("A1:A" & j).Value = OutputVal
End If
End Sub
I simply gets the Range.Value inside an array. Deleting all unused values and having one dimension as (1 To 1) allowes us to use Application.Match which is one of the fastest functions in excel.
when building up the second array, we already can check for the first one and push uniques directly to the output-array.
resizing the second array (with preserve) allowes us to use this with Match too.
Finally checking the entrys of the first array against the second one and push them also inside our output-array.
now we can directly copy the values to your destination (in one step)
Note:
- You may delete the "output-range" first (a smaller list later on will not overwrite oler values.)
- I'm not able to run real checks (you may need to report errors via comment I missed out)
- this code does not check for doubles inside one list (having 1 item 2 times in list 1 but not in list 2, will print it 2 times at the end / if you need this check, then just write a comment)
Thanks for all of your help! Here is my answer. It is mostly coming from Ron's answer - I have of course added some tweaks to it.
Sub MatchFSTradesDFTrades2()
Dim V1 As Variant
Dim V2 As Variant
Dim COL As New Collection
Dim I As Long
Worksheets("DatafileFL").Activate
With Worksheets("FundserveFL")
V1 = .Range("L1", .Cells(.Rows.Count, "L").End(xlUp)).Resize(columnsize:=7)
End With
With Worksheets("DatafileFL")
V2 = .Range("F1", .Cells(.Rows.Count, "D").End(xlUp)).Resize(columnsize:=12)
End With
For I = 1 To UBound(V1)
If V1(I, 1) = " " Or Not IsNumeric(V1(I, 1)) Or V1(I, 1) < 10000 Or V1(I, 1) = "***" Or Not IsNumeric(V1(I, 3)) Or (V1(I, 5)) = "Buy-EC" Or (V1(I, 5)) = "Sell-EC" Then
Else:
COL.Add (V1(I, 1)) & " " & (V1(I, 7)), CStr(V1(I, 1)) & " " & (V1(I, 7))
End If
Next I
For I = 1 To COL.Count
Sheet3.Cells(I + 1, 1).Value = COL.Item(I)
Next
On Error Resume Next
For I = 1 To UBound(V2)
If V2(I, 1) = "MATCHING" Then
If IsNumeric(V2(I, 5)) Then
COL.Add (V2(I, 7)) & " " & V2(I, 5), CStr(V2(I, 7)) & " " & V2(I, 5)
Select Case Err.Number
Case 457 'This is a duplicate, so will remove
Err.Clear
COL.Remove CStr(V2(I, 7)) & " " & V2(I, 5)
End Select
Else: V2(I, 12) = Right(V2(I, 5), Len(V2(I, 5)) - 1)
V2(I, 12) = Format(V2(I, 12), "General Number")
COL.Add (V2(I, 7)) & " " & V2(I, 12), CStr(V2(I, 7)) & " " & V2(I, 12)
Select Case Err.Number
Case 457 'This is a duplicate, so will remove
Err.Clear
COL.Remove CStr(V2(I, 7)) & " " & V2(I, 12)
End Select
End If
ElseIf V2(I, 5) = " " Or Not IsNumeric(V2(I, 5)) Or V2(I, 5) < 10000 Or V2(I, 5) = "***" Or V2(I, 1) = "BULK" Then
Else:
If IsNumeric(V2(I, 3)) Then
COL.Add (V2(I, 5)) & " " & V2(I, 3), CStr(V2(I, 5)) & " " & V2(I, 3)
Select Case Err.Number
Case 457 'This is a duplicate, so will remove
Err.Clear
COL.Remove CStr(V2(I, 5)) & " " & V2(I, 3)
End Select
Else: V2(I, 12) = Right(V2(I, 3), Len(V2(I, 3)) - 1)
V2(I, 12) = Format(V2(I, 12), "General Number")
COL.Add (V2(I, 5)) & " " & V2(I, 12), CStr(V2(I, 5)) & " " & V2(I, 12)
Select Case Err.Number
Case 457 'This is a duplicate, so will remove
Err.Clear
COL.Remove CStr(V2(I, 5)) & " " & V2(I, 12)
End Select
End If
End If
Next
Worksheets("ForInvestigation").Activate
Cells.Clear
For I = 1 To COL.Count
Sheet3.Cells(I + 1, 1).Value = COL.Item(I)
Next
Range("A:A").Select
Selection.TextToColumns DataType:=xlDelimited, Space:=True, Other:=True
Range("A1") = "Trade ID Number"
Range("A1").Font.Bold = True
Range("B1") = "Net Balanace On Trade"
Range("B1").Font.Bold = True
End Sub

Runtime error 91

I'm receiving the error Runtime 91 error on the line r = Bcell.Row. How do I fix the error?
Trying to define a range to perform a few checks.
Dim LastRow, SECTYPE, Bcell, r As Range
LastRow = ActiveSheet.Range("D65536").End(xlUp).Row()
Rows("1:1").Select
Selection.AutoFilter
ActiveSheet.Range("A1:L" & LastRow).AutoFilter Field:=10, Criteria1:="X"
If LastRow > 1 Then
Set SECTYPE = ActiveSheet.Range("D2:D" & LastRow)
For Each Bcell In SECTYPE
r = Bcell.Row
If Trim(Bcell.Value) = "CO" Or Trim(Bcell.Value) = "PO" Then
If (Trim(Bcell.Offset(0, -1).Value) = "SWAPOPT") And UCase(Trim(ActiveSheet.Range("i" & r).Value)) = "X" Or UCase(Trim(ActiveSheet.Range("i" & r).Value)) = "" Then
ActiveSheet.Range("J" & r).Value = "-"
ActiveSheet.Range("J" & r).Interior.ColorIndex = xlNone
End If
ElseIf Trim(Bcell.Value) = "FU" Then
If (Trim(Bcell.Offset(0, 1).Value) = 1 And InStr(Trim(Bcell.Offset(0, -2).Value), "IB") <> 0) Then
ActiveSheet.Range("J" & r).Value = "-"
ActiveSheet.Range("J" & r).Interior.ColorIndex = xlNone
End If
ElseIf Trim(Bcell.Value) = "OS" Then
If (Trim(Bcell.Offset(0, 2).Value) <> "AUD") Then
ActiveSheet.Range("J" & r).Value = "-"
ActiveSheet.Range("J" & r).Interior.ColorIndex = xlNone
End If
End If
Next Bcell
End If
You need to Set the variable like so:
Set r = Bcell.Row

Resources