和風スパゲティのレシピ

日本語でコーディングするExcelVBA

条件を満たす列を削除する - Delete/Union

特定の条件を満たす列を削除する方法を解説します。

For文でStep-1を利用して最終列から1行ずつ削除していく方法と、
Unionメソッドで一つのRangeオブジェクトにして一括削除する方法があります。


たとえば以下のようなデータにおいて、
データがすべて「0」になっている列を削除するコードを解説します。
対象データ

For文で1列ずつ削除する方法

まずはFor文で1列ずつ削除する方法がこちらです。

Sub 特定の条件を満たす列を削除_For文()

    Dim ws処理シート As Worksheet
    Set ws処理シート = Worksheets("データ")
    
    Dim 最終列 As Long
    最終列 = ws処理シート.UsedRange.Column + ws処理シート.UsedRange.Columns.Count - 1

    Dim C As Long
    For C = 最終列 To 2 Step -1

        If WorksheetFunction.Countif(ws処理シート.Columns(C), 1) = 0 Then
            ws処理シート.Columns(C).Delete
        End If
        
    Next

End Sub

 
列の削除は「Columns(列番号).Delete」で実行が可能です。

問題は列の削除を実行すると列番号がズレてしまう点で、
通常のFor文ではこの処理は正しく動きません。


例えば10,11行目に連続してすべてのデータが0の列が現れた場合、

  • COUNTIF(10列目, 1)が0なので10列目が削除される
  • 11列目だったものが10列目にスライドする
  • 次の判定は11列目、これはもともと12列目だったもの
  • 元11列目は削除されず残ってしまう

という問題が発生します。


これを避けるために、列を削除するコードを書く際は、
Step -1を指定し最終列から左に向かって逆順にループしてください。

Unionを使用して対象列を一括削除する方法

続いてUnionメソッドを用いて対象列を一括削除する方法です。

この方法であれば上記のように逆順でループする必要もない上、
処理速度も高速です。


コードを書くのが多少面倒ではありますが、
For文で速度面に問題が出たらこちらのコードを採用してください。

Sub 特定の条件を満たす列を一括削除()

    Dim ws処理シート As Worksheet
    Set ws処理シート = Worksheets("データ")
    
    Dim 最終列 As Long
    最終列 = ws処理シート.UsedRange.Column + ws処理シート.UsedRange.Columns.Count - 1
    
    Dim columns削除列 As Range
    Dim C As Long
    For C = 2 To 最終列

        If WorksheetFunction.CountIf(ws処理シート.Columns(C), 1) = 0 Then
            If columns削除列 Is Nothing Then
                Set columns削除列 = ws処理シート.Columns(C)
            Else
                Set columns削除列 = Union(columns削除列, ws処理シート.Columns(C))
            End If
        End If
        
    Next
    
    If Not columns削除列 Is Nothing Then
        columns削除列.Delete
    End If

End Sub

 
Unionメソッドを使用すると、Rangeオブジェクト同士を結合し、
ひとつのRangeオブジェクトにする
ことができます。


これを利用して削除する列をRangeオブジェクトに貯めていき、
すべての列の判定が終わってから一括削除を実行しています。


例えばループ後にAddressを確認してみると、

Debug.Print columns削除列.Address
' $B:$C,$E:$G,$I:$K,$M:$P,$R:$S

このように複数列がひとつのRangeオブジェクトに格納されているのが分かります。

後はこれを.Deleteで削除すればよいわけですね。


Unionメソッドで注意しなければいけないのが、
引数にNotingを渡すとエラーになってしまう点です。


以下のようにNotingであればUnionを使用しない分岐を書いておかないと、
第1実行時にエラーとなってしまうためご注意ください。

If columns削除列 Is Nothing Then
    Set columns削除列 = ws処理シート.Columns(C)
Else
    Set columns削除列 = Union(columns削除列, ws処理シート.Columns(C))
End If

 

以上で特定の条件を満たす列を削除する方法の解説を終わります。

速度面ではUnionによる一括削除が勝りますが、
Step-1方式の方がコーディングが楽というメリットがあります。


普段はFor文で書き、速度面で気になったらUnionを使用するなど、
状況に応じて使い分けてください。