Reputation: 25
I am writing a VBA macro for excel to remove columns I don't have specific headers for. I have come close but have run into an odd problem with the way the columns remove.
I am using a simple nested IF. The odd thing is when I run my code it only removes every OTHER column that is not in my list. I have to run the macro 4 or 5 times to get the wanted result. This code is meant to be part of a larger macro and will be for other users as well so getting it to work right the first time is key.
Sub DeleteColumns()
Set MR = Range("A1:W1")
For Each cell In MR
If cell.Value <> "Cartons" Then
If cell.Value <> "ShipVia" Then
If cell.Value <> "Name" Then
If cell.Value <> "Address" Then
If cell.Value <> "City" Then
If cell.Value <> "State" Then
If cell.Value <> "Zip" Then
cell.EntireColumn.Delete
End If
End If
End If
End If
End If
End If
End If
Next
End Sub
Upvotes: 2
Views: 834
Reputation:
@urdearboy is absolutely correct in his diagnosis of the problem. Here is my solution as a variation on the theme of Select Case
which happens to be an approach that is both compact and very descriptive (readable).
Sub DeleteColumns()
Dim LastCol As Long
Dim i As Long
LastCol = ActiveSheet.Range("A1:W1").Cells.Count
i = 1
Do
Select Case ActiveSheet.Cells(1, i)
Case "Cartons", "ShipVia", "Name", "Address", "City", "State", "Zip"
i = i + 1 ' this column is to remain; examine the next column
Case Else
ActiveSheet.Cells(1, i).EntireColumn.Delete
LastCol = LastCol - 1 ' as you delete columns the right margin moves in
' do not increment "i" because the next column moves in place automatically
End Select
Loop Until i > LastCol
End Sub
Hope this helps to illustrate the "mechanics" of column deletion.
To have more efficiency in the code (in light of the above) we need to start from the right so that only one "positional" variable is required:
Sub DeleteColumns()
Dim i As Long
i= ActiveSheet.Range("A1:W1").Cells.Count
Do
Select Case ActiveSheet.Cells(1, i)
Case Is <> "Cartons", "ShipVia", "Name", "Address", "City", "State", "Zip"
ActiveSheet.Cells(1, i).EntireColumn.Delete
End Select
i = i - 1
Loop While i > 0
End Sub
And, of course, this can be easily generalized for the situations when, for example, the range does not start in column "A", etc.
Upvotes: 0
Reputation: 14580
The issue you are seeing is due to the fact that you are deleting columns inside your loop range. When you delete a column, the range you are looping through shifts and this causes columns to be skipped (consistent with your results). To combat this, you can use the Union
method which allows you to delete columns outside of the loop so you will not experience the reported issue. The bottom solution shows how to fix the reported issue if you do decide to delete columns inside the loop.
Select Case
would be my preferred method. Loop through the range and if the cell is not in listed in the first case, it will be flagged to be deleted in the second case (Case Else
).
Once you have looped your headers, delete the columns all at once which means there is no range shift while looping.
Sub DeleteColumns()
Dim iCell As Range, DeleteMe As Range
For Each iCell In Range("A1:W1")
Select Case iCell
Case "Cartons", "ShipVia", "Name", "Address", "City", "State", "Zip"
'Do Nothing
Case Else
If Not DeleteMe Is Nothing Then
Set DeleteMe = Union(DeleteMe, iCell)
Else
Set DeleteMe = iCell
End If
End Select
Next iCell
If Not DeleteMe Is Nothing Then DeleteMe.EntireColumn.Delete
End Sub
You could also loop through an array. Note that the column loop is going backwards to stop the relevant range from shifting inside the loop (your initial problem). To do this, you will need to drop the For Each
loop and switch to the For j = # - #
so you can utilize the Step -1
property
Sub Array_Method()
Dim Arr: Arr = Array("Cartons", "ShipVia", "Name", "Address", "City", "State", "Zip")
Dim i As Long, j As Long
For j = 23 To 1 Step -1
For i = UBound(Arr) To LBound(Arr)
If Arr(i) = Cells(1, j) Then
Cells(1, j).EntireColumn.Delete
End If
Next i
Next j
End Sub
Upvotes: 4