[[20220313003116]] 『コードをまとめたい』(八家) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『コードをまとめたい』(八家)

VBA覚えたての初心者です。
よろしくお願いいたします。

ある一行において、
その行に目的のセルがあればメッセージボックスが表示させ、
5行分だけ下がって、
再度、同様の処理を20回分したい・・とします。

とりあえず、3行分ほどはできました。

:::::::::::::::::::::::::::::::
Sub ボタン6_Click()

  Dim i As Long
    For i = 5 To 32
      If Cells(9, i) = Cells(1, 1).Value Then
        msg = MsgBox(Cells(8, 2))
      End If
    Next i

  Dim t As Long
    For t = 5 To 32
      If Cells(14, t) = Cells(1, 1).Value Then
        msg = MsgBox(Cells(13, 2))
      End If
    Next t

  Dim s As Long
    For s = 5 To 32
      If Cells(19, s) = Cells(1, 1).Value Then
        msg = MsgBox(Cells(18, 2))
      End If
    Next s

End Sub
:::::::::::::::::::::::::::::::

ただ、20個分もコードを書くのはいかがなものかと考え、これをどうかしてもう少しまとめられないかと考えたところ、
offset と do loop という関数があると知りました。
何とか書き換えましたが全く動きません。
何がダメなのか教えていただけないでしょうか。

以下自作コード

:::::::::::::::::::::::::::::::
Sub ボタン6_Click()

  Dim i As Long

  Do
  t = 0
    	For i = 5 To 32
      		If Cells(9, i).Offset(t) = Cells(1, 1).Value Then
        		msg = MsgBox(Cells(8, 2).Offset(t))
        		Exit Do
      		Else
        		Exit Do
      		End If
    	Next i
    t = t + 5
  Loop

End Sub

< 使用 Excel:Excel2019、使用 OS:Windows10 >


 ちょっと...良く見てないのでこれで意味合いが
 合っているか確認してください。

 19行目までの範囲を対象にしてあるので
 残りは調整してください。

 Sub Sample()
    Dim i As Long, j As Long
    Dim msg As VbMsgBoxResult
    For i = 5 To 32
        For j = 9 To 19 Step 5
            If Cells(9, i) = Cells(1, 1).Value Then
                msg = MsgBox(Cells(j - 1, 2))
            End If
        Next j
    Next i
 End Sub
(あみな) 2022/03/13(日) 01:19

あみなさま
即レスありがとうございます。
まことに申しにくいのですが、
一番最初の処理する行に該当のセルがない場合、なにも起動しません
これはどうしてでしょうか・・?
(八家) 2022/03/13(日) 01:32

 >一番最初の処理する行に該当のセルがない場合、なにも起動しません

 これならどうかな?

 Sub Sample()
    Dim i As Long, j As Long
    Dim msg As VbMsgBoxResult
    For i = 5 To 32
        For j = 9 To 19 Step 5
            If Cells(j, i).Value = Cells(1, 1).Value Then
                msg = MsgBox(Cells(j - 1, 2))
            End If
        Next j
    Next i
 End Sub

(あみな) 2022/03/13(日) 01:42


あみなさま!
うまくできました!
ありがとうございました。
夜分遅くに本当にありがとうございました。
(八家) 2022/03/13(日) 01:45

 後は、わかると思うので頑張ってちょだいね。^^

(あみな) 2022/03/13(日) 01:51


ありがとうございました!!
(八家) 2022/03/13(日) 02:03

 If Cells(9, i).Offset(t) = Cells(1, 1).Value Then
 の成立の如何にかかわらず Exit Do で抜けてしまうことが原因でしょう。

 されたいことが不明なので、形式的に整えただけですが、
 こんな形の「入れ子」のループになるのでは?

 Sub ボタン6_Click()
     Dim k As Long
     Dim i As Long
     Dim msg
     For k = 9 To 9 + 5 * 19 Step 5
         For i = 5 To 32
             If Cells(k, i) = Cells(1, 1) Then
                 msg = MsgBox(Cells(k - 1, 2))
                 ''Exit For '一つでも一致したら警告出力なら、直ぐに抜ければよいかも。
             End If
         Next i
     Next
 End Sub
 # なお、一致するものがあるかどうかだけなら、
 # MATCH関数とか、COUNTIF関数とかを使うかもしれませんねえ。

(γ) 2022/03/13(日) 05:57


 おはようございます。											
 (八家)さん、見に来てください!! ^^;											

 えっ?何かってですよね?											
 先に結論から言いますと、(γ)さん書いてくださったループ処理が正です。											
 (γ)さん、ありがとうございます。											

 なにかって言いますと…二重ループの基本?の走らせ方は											
 横方向が先で、縦は後になると思うのですが											
 私が適当で^^;…その〜どっちからでもいいじゃん的な考えで											
 あ、すいません。言ってる事がわからないですよね?											

 えと、二重ループには、内側ループと外側ループがありまして											
 書き方によって横に先に走らせるか、縦に走らせるかを決めることが											
 できるのです。											

 実際の処理は一瞬なので人間さんの目には見えないですが											
 一つのセルに背景色を付けながら処理すると理解できます。											
 今回の、(八家)さんの場合は横が正なので(きっと)と思います。											

 IF文をコメントアウトして下記のコードを実行すると											
 走り方がわかるので19行目までで試してください。											

 Sub 列方向優先チェック()											
    Dim i As Long, j As Long, x As Long											
    Dim msg As VbMsgBoxResult											
    For i = 5 To 32											
        For j = 9 To 19 Step 5											
            ''If Cells(j, i).Value = Cells(1, 1).Value Then											
                Cells(j, i).Interior.Color = RGB(175, 238, 238)											
                msg = MsgBox(Cells(j - 1, 2))											
            ''End If											
        Next j											
    Next i											
 End Sub											

 Sub 行方向優先チェック()											
    Dim i As Long, j As Long, x As Long											
    Dim msg As VbMsgBoxResult											
    For j = 9 To 19 Step 5											
        For i = 5 To 32											
            ''If Cells(j, i).Value = Cells(1, 1).Value Then											
                Cells(j, i).Interior.Color = RGB(175, 238, 238)											
                msg = MsgBox(Cells(j - 1, 2))											
            ''End If											
        Next i											
    Next j											
 End Sub											

(あみな) 2022/03/13(日) 07:42


γ様、 あみな様
ここまでご丁寧にありがとうございます。
このコードをもとにもう一度勉強したいと思います。
本当にありがとうございました
(八家) 2022/03/13(日) 10:36

 よく見に来たでありんす^^

 デバッグ Debug.Print(変数)もしっかりして頑張ってね。

(あみな) 2022/03/13(日) 11:02


 コメントありがとうございました。

 ■以下、余談です。(お急ぎの方は、そのままスキップしてください)

 話は、配列を行方向に処理するか、列方向に処理するかの順序に関するものです。

 VBAの配列は、列優先順序のメモリーレイアウトを利用していると思います。
 つまり、行列(例えば2次元配列)はメモリー上に
    1    5    9
    2    6   10
    3    7   11
    4    8   12
 といった数値をつけた位置の順番にメモリー上に管理されているものと思われます。
 (メモリーはむろん一次元です)

 動的配列のRedim Preserveなどで、「最後の次元に沿ってしか大きさを変更できない」というのは、
 このメモリーレイアウトが原因となっているわけです。

 動的配列と固定配列のメモリーレイアウトは同じであると仮定すると、
 上の"列優先順序"で配列にアクセスしたほうが、連続した位置のメモリーを扱うことになるので、
 速度的にも有利なはずです。

 実験してみました。
 縦横1000要素からなる二次元配列に、1000個の要素からなる一次元配列を
 (c)縦に配置して全体に繰り返して埋める処理を100回実行
 (r)横に配置して全体に繰り返して埋める処理の100回実行
 の時間を計測すると、
 (c)は1.97秒、(r)は2.20秒と、(c)は約9割の時間で済みます。(10回の平均値)
 (もちろん出来上がりの配列は異なりますが、処理時間にのみ注目しています)

 (なお、私の別の処理系(これも列優先順序のルールに従います)で同じ実験をすると、
   (c)0.0741秒  (r)0.1846秒と、(c)は(r)の約4割の時間で済みました。)

 ですから、理屈からいうと、ループは、速度面だけから言えば、
     For j = 1 To n
         For i = 1 To n
             mat(i, j) = ary(i)
         Next
     Next
 のように列方向を優先するのが有利ということになります。

 しかし、(今回の例のように)ユーザーの目的が、、
 上の行から始めて、順次横方向で比較を行い、
 次の行に処理を進める、
 といったものであれば、速度のことはさておいて、
 そうした処理をそのままコード化する必要があるものと思います。

 列優先と行優先の速度の話は余り目にしたことがなかったので、
 参考のためにメモしてみました。

 ■【追記】ワークシート上の計算順序について。
 VBAのヘルプによると、
 > Rangeオブジェクトには、CalculateRowMajorOrderというメソッドがあり、
 > これは、セルごとに、左上隅から右下隅まで、行優先順に指定された範囲を計算します。
 > これは、Excel2000以前のバージョンで範囲を計算するために使用されるプロセスと同じです。
 ということは、現在のExcelのワークシート計算は上記の行優先ではなく、
 デフォルトでは、列優先順序で計算がされている、ということのようです。

(γ) 2022/03/13(日) 18:46


参考サイトは下記です。
"Row- and column-major order"
https://en.wikipedia.org/wiki/Row-_and_column-major_order#Programming_languages_and_libraries
(γ) 2022/03/13(日) 18:48

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.