選択した順にセルの値を取得

セルを一つずつクリックする。次いで、選択した順序で選択した値を取得したい。そのような要件があった。
f:id:Infoment:20181021214144p:plain

例えば、このようなケースだ。
f:id:Infoment:20181021214224p:plain

  1. 1から5まで一つずつ選択
  2. 20から16まで一つずつ選択
  3. 21から25まで一つずつ選択

まずは安易に、配列に格納してみる。

Sub test()
    Dim seq As Variant
        seq = Selection
        
    Dim s As Variant
        For Each s In seq
            Debug.Print s
        Next
End Sub

結果、エラーが出た。
f:id:Infoment:20181021215318p:plain

確認したところ、単独セルの値をVariant型の変数に入れると、配列ではなく値になるためのようだ。また、複数セルが選択されていたとしても、これでは次の選択範囲が処理対象とならない。

そこで、次のように変更してみた。

Sub test2()
    Dim seq() As Variant
    ReDim seq(0)
    Dim Area As Range
    Dim r As Range
        For Each Area In Selection.Areas
            For Each r In Area
                seq(UBound(seq)) = r.Value
                ReDim Preserve seq(UBound(seq) + 1)
            Next
        Next
        ReDim Preserve seq(UBound(seq) - 1)
        
    Dim s As Variant
        For Each s In seq
            Debug.Print s
        Next
End Sub

Areasコレクションで、各選択範囲の各セルの値を一つずつ配列に格納していく。これはこれで上手くいったが、ちょっと大掛かりな感じがする。


そこで、選択範囲をRangeオブジェクトのまま変数に入れてみた。

Sub test3()
    Dim myRng As Range
        Set myRng = Selection
        
    Dim r As Range
        For Each r In myRng
            Debug.Print r
        Next
End Sub

これも上手くいったが、myRngにはセルの番地やフォント名など、不要な情報もたくさん引き連れている。ちょっと無駄が多い気がする。


最後に、選択範囲の値をコレクションに入れてみた。

Sub test4()
    Dim col As Collection
    Set col = New Collection
    
    Dim r As Range
        For Each r In Selection
            col.Add r.Value
        Next

    Dim c As Variant
        For Each c In col
            Debug.Print c
        Next
End Sub

これも上手くいった。単なる好みの問題なので上手く説明できないが、この方法が一番しっくりくる。


手法の良し悪しはさておき、ある目的を達成する手段を複数知っているというのは、多分良いことに違いない。と思う。

参考まで。