Reputation: 334
I have created an Excel collection from an Excel Column by using a FOR iteration through that column. However, this collection includes the header and blank columns. I wish to remove these blank columns and the header from the collection and do not know how. Based on my code, I keep receiving a Runtime Error 5
I have tried to use a For Each iteration through the collection and collection_name.Remove element based on a conditional which you can see below, but this has not worked.
Public Sub outer_lÖÖp()
'creating a collection of the policy numbers
Sheets("MappingSheet").Select
Dim policynums As New Collection
Dim i As Integer
For i = 1 To 100
policynums.Add (Cells(i, 1))
Next i
'getting rid of "Policy Number" and empty strings from collection
Worksheets("GL").Activate
For Each element In policynums
If element = "Policy Number" Or element = "" Then
policynums.Remove element
End If
Next element
For Each element In policynums
MsgBox (CStr(element))
Next element
End Sub
This keeps returning a Runtime Error 5, invalid procedure element or call. How can I solve my problem and remove all irrelevant strings from this collection?
Upvotes: 0
Views: 462
Reputation: 71187
The data is coming from a specific worksheet. First step is to get that object.
Dim sheet As Worksheet
'TODO make this work off a Workbook object so we don't need to care what workbook is currently active.
Set sheet = ActiveWorkbook.Worksheets("MappingSheet")
Next, we want a collection object - avoid As New
, it makes an auto-instantiated object, and that has consequences you really don't want to be dealing with.
Dim elements As Collection
Set elements = New Collection
Next we loop 1 To 100
. While that does fit the Integer
range, we avoid the legacy 16-bit integer type, especially for something like a row number, which can be in the millions: use a Long
instead, a 32-bit integer type.
Dim currentRow As Long
For currentRow = 1 To 100 'TODO determine how many rows we need before we start looping.
elements.Add sheet.Cells(currentRow, 1).Value
Next
Now, why iterate the collection again, just to remove things that shouldn't have been added in the first place?
Dim currentRow As Long
For currentRow = 1 To 100 'TODO determine how many rows we need before we start looping.
Dim cell As Range
Set cell = sheet.Cells(currentRow, 1)
If Not IsError(cell.Value) Then
If Trim$(cell.Value) <> vbNullString And cell.Value <> "Policy Number" Then
elements.Add sheet.Cells(currentRow, 1).Value
End If
End If
Next
If the only reason to check for the "Policy Number"
literal is to avoid the first record which is your row heading, remove that check, and start looping at row 2 instead -- assuming the table header is in row 1:
For currentRow = 2 To 100 'TODO determine how many rows we need before we start looping.
Dim cell As Range
Set cell = sheet.Cells(currentRow, 1)
If Not IsError(cell.Value) Then
If Trim$(cell.Value) <> vbNullString Then
elements.Add sheet.Cells(currentRow, 1).Value, Key:="Row" & currentRow
End If
End If
Next
Notice the Key
named argument (only named for clarify in this post - it doesn't have to be named.. although it doesn't hurt either): if you wanted to remove the item keyed with "Row12"
from the collection, you would do this:
elements.Remove "Row12"
Lastly, MsgBox
(and any other procedure call for which you aren't capturing the return value) should look like this:
MsgBox element
The extraneous parentheses have a syntactic meaning that you are probably not expecting. This wouldn't compile:
MsgBox (element, vbInformation)
Because the parentheses are telling VBA to evaluate their contents as a value expression, and pass the result of that expression ByVal to the invoked procedure. But (foo, bar)
isn't a valid expression, so the code refuses to compile.
In any case, rule of thumb you want to Debug.Print
the contents of a collection, or just use the debugger toolwindows to inspect its contents - a MsgBox
in a loop is obnoxiously annoying!
Upvotes: 2