Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


44 / 13014 ツリー ←次へ | 前へ→

【79007】等間隔の行数取得 boss 17/4/13(木) 19:43 質問[未読]

【79024】Re:等間隔の行数取得 boss 17/4/17(月) 16:17 質問[未読]
【79031】Re:等間隔の行数取得 γ 17/4/17(月) 21:25 発言[未読]
【79033】Re:等間隔の行数取得 γ 17/4/18(火) 7:38 発言[未読]
【79036】Re:等間隔の行数取得 boss 17/4/18(火) 10:20 発言[未読]
【79037】Re:等間隔の行数取得 β 17/4/18(火) 10:56 発言[未読]
【79038】Re:等間隔の行数取得 β 17/4/18(火) 11:12 発言[未読]
【79039】Re:等間隔の行数取得 boss 17/4/18(火) 11:46 発言[未読]
【79040】Re:等間隔の行数取得 β 17/4/18(火) 13:37 発言[未読]
【79041】Re:等間隔の行数取得 boss 17/4/18(火) 18:50 お礼[未読]
【79035】Re:等間隔の行数取得 β 17/4/18(火) 9:33 発言[未読]

【79024】Re:等間隔の行数取得
質問  boss  - 17/4/17(月) 16:17 -

引用なし
パスワード
   以前させていただいた質問の内容が誤っており、以下のとおり訂正させてください。

K13、K20、K27・・・、と等間隔で「あああ」と入力されており、K列の最後に「最終」
と入力されている行があります。
1.にて「最終」行を取得 2.にてK13を先ずは取得し 3.にて「最終」行までK20、K27
以降を取得しようとしておりますが、3.のK20以降が取得できません。
尚、3.は別のfor分中にある構文です。
お手数ですがご教授の程よろしくお願いいたします。

  '1.「最終」行を決定
  maxrow = sh1.Cells(Rows.Count, "K").End(xlUp).row
  ttlrow = 0
  For row = 7 To maxrow
    If sh1.Cells(row, "K").Value = "最終" Then
      ttlrow = row
      Exit For
    End If
  Next
  If ttlrow = 0 Then '"最終"の合計行
    MsgBox ("最終の行がありません" & vbLf & "処理を打ち切ります")
    Exit Sub
  End If

  '2.「あああ」行を取得
  maxrow = sh1.Cells(Rows.Count, "K").End(xlUp).row
  ttlrow2 = 0
  For row2 = 12 To maxrow2
    If sh1.Cells(row2, "K").Value = "あああ" Then
      ttlrow2 = row2
      Exit For
    End If
  Next
  If ttlrow2 = 0 Then
    MsgBox ("あああ行がありません" & vbLf & "処理を打ち切ります")
    Exit Sub
  End If


  '3.以降の「あああ」行を取得
  For row2 = ttlrow2 + 1 To maxrow
    If sh1.Cells(row2, "K").Value = "あああ" Then
      ttlrow2 = row2
    End If
  Next
  If ttlrow2 = 0 Then
    MsgBox ("あああ行がありません" & vbLf & "処理を打ち切ります")
    Exit Sub
  End If

【79031】Re:等間隔の行数取得
発言  γ  - 17/4/17(月) 21:25 -

引用なし
パスワード
   >   '3.以降の「あああ」行を取得
>   For row2 = ttlrow2 + 1 To maxrow
>     If sh1.Cells(row2, "K").Value = "あああ" Then
>       ttlrow2 = row2
>     End If
>   Next

  (ttlrow2 + 1)行 から maxrow行まで
  一行ずつ見ていって、"あああ"と一致はするけれども、
  単に、 ttlrow2 = row2 を実行しているだけですから。
  ttlrow2という変数に上書きしていっているだけです。

  ttlrow2 = row2
  に代えて、そこに、なにかしら実行したいことを書いたらどうですか?

【79033】Re:等間隔の行数取得
発言  γ  - 17/4/18(火) 7:38 -

引用なし
パスワード
   >'3.以降の「あああ」行を取得
3.以降の「あああ」行は複数あるんでしょう?
それに対して、どんなことを実行したいのですか?
肝心なことが書かれていないので、改善策も書けない。

【79035】Re:等間隔の行数取得
発言  β  - 17/4/18(火) 9:33 -

引用なし
パスワード
   ▼boss さん:

横から失礼します。

bossさんとしては、『何かをしたい』んですよね。
それを「要件」と呼びましょうか。
で、その要件を実現するために、コードをあれこれ考えられるわけですよね。
それを コードレベルの「仕様」と呼びましょうか。

で、たとえば

 1.ttlrow2に行数を取得
 2.にてdict(key)の値をセット
 3.TからNTの範囲で、ttlrow2の行に罫線をひく

こう説明されたわけです。
でも、これって、あくまで、本当の要件ではなく要件を実現しようとして
bossさんが頭の中で作り上げられたコード仕様ですよね。
失礼ながら、もしかしたら、このコード仕様そのものが要件を実現するうえで
必ずしも適切なものではないかもしれません。

いいかえれば、回答側から見て、コード仕様を提示されても、なんのために何をしようとしているのかなと
そこがわかりづらくなります。

コードは横におき、

・どんなレイアウトのシートがある
・そこで、どんなことを判定し、条件ごとに どんなことをやりたい

そういうことを『言葉』で、明確に説明されてはいかがですか。

【79036】Re:等間隔の行数取得
発言  boss  - 17/4/18(火) 10:20 -

引用なし
パスワード
   ▼γ さん:
>>'3.以降の「あああ」行を取得
>3.以降の「あああ」行は複数あるんでしょう?
>それに対して、どんなことを実行したいのですか?
>肝心なことが書かれていないので、改善策も書けない。

ご回答ありがとうございます。言葉のみでうまくご説明できるか自信ございませんが。。。
画像等をリンクできれば良いのですが、本サイトの基本方針にそれらの記載が無かったので良し悪し判断できませんでした。
ですので、一先ず言葉のみで。全てのソースもだらだら長いだけですし。

作っているのは必要部品スケジュールです。
作業の一括りは作業1から作業2、作業3・・・と続きます。
例えば、作業1の作業1−1では必要部品が5個、作業1−2では必要部品が100個となり、作業1の必要部品は105個となります。
Sheet1はスケジュール表で、T列までは作業の開始日、終了日、部品日を記載し、T列以降の2017/1/1と〜2017/12/31に開始日から終了日までの期間を指定した色で塗潰し、部品名を転記します。
Sheet2は部品数の表で、作業1−1→5個、作業1−2→100と、BOMをイメージいただければ良いかと思います。Scripting.Dictionaryで配列を取得しました。

質問させていただいた内容は、Sheet1に作業単位で「部品小計」という行を設け、日別の必要部品数小計を表示しようとしております。
質問の「あああ」が「部品小計」に該当します。
ステップ実行にて確認したのですが、先の2.ではttlrow2 = row2ができているのですが、3.ではttlrow2 = row2がとおっていないのが原因まではなんとなく分っているのですが。

おそらく説明内容不十分と思いますが、大凡イメージ伝わりましたでしょうか?

【79037】Re:等間隔の行数取得
発言  β  - 17/4/18(火) 10:56 -

引用なし
パスワード
   ▼boss さん:

説明では 

>K13、K20、K27・・・、と等間隔で「あああ」と入力されており、K列の最後に「最終」

とありますが、最終を求めるコードが K7 から下にさがしていますよね。
また あああ を求めるコードは K12 から下にさがしています。

K列 最終 となっているセルの下にも値があるのかどうか、等間隔の あああ は
ずっと等間隔で続いて存在するのか、どこか、本来存在するセルが空白で、でも、その下の等間隔の場所には
あああ が再び現れるのか、説明がないのでわかりませんが
少なくとも説明を踏まえるなら 最終 も あああ も K13 から K列のデータ最終セルまでの間をさがさなければ
いけないのではないですか?

さらに、あああ ですけど、(おそらく 最終 も?)等間隔で存在するということですけど
コードでは、間隔を無視して1行ずつチェックしてますよね。
等間隔ではないところに あああ や 最終 が、もし記述されていれば、そこが対象になりますけど
いいのでしょうかね?

何を言いたいかといいますと、やはり、要件を明確に言葉で説明いただかないと、コードが間違っていたとして
その間違ったコードをもとに、あれこれ議論しても、無駄になることが少なくないということです。

ところで、(等間隔 ということを無視すれば)あああ や 最終 は、行をすべてなめまわさなくても
Find や FindNext で取得できますよ。
等間隔ということを含めるなら 取得したセルの行番号をチェックして対象セルかどうかを判定すれば
よろしいかと。

それと、

MsgBox ("最終の行がありません" & vbLf & "処理を打ち切ります")

よく見かける 「間違い記述」です。
今回の記述では結果オーライですが、メッセージを ( ) で囲むのは、実は間違っています。
詳細は割愛しますが

MsgBox "最終の行がありません" & vbLf & "処理を打ち切ります"

と記述する習慣を早くつけられたらいいと思います。

【79038】Re:等間隔の行数取得
発言  β  - 17/4/18(火) 11:12 -

引用なし
パスワード
   ▼boss さん:

参考になるかどうか K13 から K列データ最終セルまでの間の 
最終 と あああ のセルを取得するサンプルです。

等間隔 というところは無視しています。
ここで、取得される g や a の領域を相手に、好きな処理をどうぞ。
a は セルの集合体ですから、その中から1つずつ取り出して処理するのもよし
処理要件によっては a に対して一括処理もできるでしょう。

Sub Sample()
  Dim sh1 As Worksheet
  Dim g As Range
  Dim c As Range
  Dim f As Range
  Dim a As Range
  Dim ttlrow As Long
  Dim r As Range
  
  Set sh1 = Sheets("Sheet1")
  Set r = sh1.Range("K13", sh1.Range("K" & Rows.Count).End(xlUp))
  
  Set g = r.Find(What:="最終", LookAt:=xlWhole, SearchDirection:=xlPrevious)
  If g Is Nothing Then
    MsgBox "最終の行がありません" & vbLf & "処理を打ち切ります"
    Exit Sub
  End If
  
  ttlrow = g.Row
  
  MsgBox "最終は " & ttlrow & "行目にありましたよ"
  
  Set c = r.Find(What:="あああ", LookAt:=xlWhole, After:=r.Cells(r.Count))
  
  If c Is Nothing Then
    MsgBox "あああ の行がありません" & vbLf & "処理を打ち切ります"
    Exit Sub
  End If
  
  Set f = c
  
  Do
    If a Is Nothing Then
      Set a = c
    Else
      Set a = Union(a, c)
    End If
    
    Set c = r.FindNext(c)
    
  Loop While c.Address <> f.Address
  
  MsgBox "あああ は 以下に存在しています" & vbLf & a.Address(External:=True)
  
End Sub

【79039】Re:等間隔の行数取得
発言  boss  - 17/4/18(火) 11:46 -

引用なし
パスワード
   ▼β さん:
ご助言ありがとうございます。βさんの助言を見る前に【79036】を記載してしまいました。
ご指摘の「要件」も不明瞭で仰るとおりです。申し訳ございません。
いただいたサンプルをもとに頑張ってみます。結果は後報いたします。
先ずは御礼です。

【79040】Re:等間隔の行数取得
発言  β  - 17/4/18(火) 13:37 -

引用なし
パスワード
   ▼boss さん:

Dictionary で制御する案も2つほどアップしておきます。

コードでは K列 13行目から最終行までの間で 7行ごとに処理しています。
Sample2,Sample3 、基本的に同じことをしているんですが、Sample2 のほうは
取得する あああ アドレスを Range("K13,K20,K27,・・・") といったようにしています。
この Range内のアドレス文字列が 255桁を超えるとエラーになります。

そういう心配があるなら、Sample2 のように該当のセルを1つずつ取り出して処理することが
必要になります。

Sub Sample2()
  Dim dic As Object
  Dim i As Long
  Dim mx As Long
  Dim sh1 As Worksheet
  Dim c As Range
  Dim g As Range
  
  Set sh1 = Sheets("Sheet1")
  Set dic = CreateObject("Scripting.Dictionary")
  mx = sh1.Range("K" & Rows.Count).End(xlUp).Row
  
  For i = 13 To mx Step 7
    Set c = sh1.Cells(i, "K")
    Select Case c.Value
      Case "最終": Set g = c
      Case "あああ": dic(c.Address(False, False)) = True
    End Select
  Next
  
  If g Is Nothing Then
    MsgBox "最終 がありません" & vbLf & "処理を打ち切ります"
  ElseIf dic.Count = 0 Then
    MsgBox "あああ がありません" & vbLf & "処理を打ち切ります"
  Else
    MsgBox "最終 は " & g.Address(External:=True) & vbLf & _
      "あああ は " & sh1.Range(Join(dic.keys, ",")).Address(External:=True)
  End If
  
End Sub

Sub Sample3()
  Dim dic As Object
  Dim i As Long
  Dim mx As Long
  Dim sh1 As Worksheet
  Dim c As Range
  Dim g As Range
  Dim d As Variant
  
  Set sh1 = Sheets("Sheet1")
  Set dic = CreateObject("Scripting.Dictionary")
  mx = sh1.Range("K" & Rows.Count).End(xlUp).Row
  
  For i = 13 To mx Step 7
    Set c = sh1.Cells(i, "K")
    Select Case c.Value
      Case "最終": Set g = c
      Case "あああ": Set dic(c.Address(False, False)) = c
    End Select
  Next
  
  If g Is Nothing Then
    MsgBox "最終 がありません" & vbLf & "処理を打ち切ります"
  ElseIf dic.Count = 0 Then
    MsgBox "あああ がありません" & vbLf & "処理を打ち切ります"
  Else
    MsgBox "最終 は " & g.Address(External:=True) & vbLf & _
          "いまから あああ のセルを1つずつ表示します"
    For Each d In dic.items
      MsgBox d.Address(External:=True)
    Next
    
  End If
  
End Sub



【79041】Re:等間隔の行数取得
お礼  boss  - 17/4/18(火) 18:50 -

引用なし
パスワード
   ▼β さん:
▼γ さん:

お二方にご助言いただいた方法にて、試行錯誤して何とか結果が出せました!
色々勉強になり、本当にありがとうございました。
拙い説明であったりで、ご迷惑をお掛けいたしましたことお詫びいたします。

44 / 13014 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free