Excel (VBA)

Excel VBAに関するフォーラムです。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(Windows 10 Pro : Excel 2016)
簡潔で分かりやすいコードを書きたいです
投稿日時: 19/08/13 21:12:26
投稿者: obon

下の問題を解くコードを簡潔にわかりやすく書きたいです。
for文を何重かに重ねる方法になりますでしょうか。
良い書き方がありましたら教えていただけますでしょうか。
 
やりたいこと:
使用できる時間が決まっているマシンA(60分), マシンB(30分), マシンC(30分)を使って、
パン1〜4、おにぎり1〜4、お菓子1〜2を作りたいです。
それぞれどのマシンで作ったら良いかを計算し、結果(赤文字部分)をセルに書き込みたいです。
パン1〜4、おにぎり1〜4、お菓子1〜2は、
マシンA, マシンB, マシンCどれで作るかによって作るのにかかる時間が異なっています。
(パン1の場合、マシンA 30分、マシンB 50分、マシンC 50分)
 
エクセル表の例: (赤文字部分のセルを埋めたいです)
 
     使用可能時間    結果_使用時間
マシンA   60     60
マシンB   30     30
マシンC   30     30
 
 
      作るのにかかる時間
    マシンA マシンB マシンC 結果_使用マシン
パン1     30     50     50        マシンA
パン2     20     30     30        マシンA
パン3     15     25     25        マシンB
パン4     10     20     20        マシンA
おにぎり1  9     13     13      マシンC
おにぎり2  7     10     10      マシンC
おにぎり3  5     7     7      マシンC
おにぎり4  3     5     5      マシンB
お菓子1       2     3     4      NG
お菓子2       1     2     3      NG
 
 
方法
マシンA→B→Cの順に、使用可能時間の範囲で作るものを決めていきます。
順番は、パン1→お菓子2の順に 上の行から下に向かって見ていきます。
 
例えばマシンAについてみると、
    マシンA マシンB マシンC    合計   備考
パン1     30     50     50        30 → ≦ 60 なので マシンA
パン2     20     30     30        50 → ≦ 60 なので マシンA
パン3     15     25     25        65 → > 60 なので 一旦おいとく
パン4     10     20     20        60 → == 60 なのでマシンA
    
といった具合に、上から足していって使用可能時間の範囲内で作れるものを足していきます。
マシンの時間が埋まったり、お菓子2まで走査を終えた場合は、
次のマシンBで何を作るか マシンが決まっていない行について同様に走査します。
 
for文を何回か回してということになると思っていますが
簡潔なコードとする場合 どういう書き方になりますでしょうか。宜しくお願い致します。

回答
投稿日時: 19/08/13 22:11:58
投稿者: simple

こんばんは。
これは何かの課題でしょうか?
ご自分ではどこまでトライされていますか?
できているところまで示してもらえますか?

回答
投稿日時: 19/08/14 00:33:37
投稿者: MMYS

「簡潔にわかりやすく」
の前に大前提があります。
 
それは汚くても良いので自力で正常に動作するコードを書く。です。
 
今回の案件ならまず「パン1」だけの処理を考えます。
このとき重要なのはパン2やパン3のことは一切考えないことです。
つまり「パン1」専用のコードを作るのです。
 
「パン1」専用のコードが完成したら「パン1」のコードをコピペして
「パン2」専用のコードを作ります。
 
「パン2」専用のコードが完成したら
「パン3」専用のコードを作ります。
 
そしてこれをメインから呼び出します。

Sub main()
  Call Pan1
  Call Pan2
  Call Pan3
End Sub

Sub Pan1()
  'パン1を処理するコード
End Sub

Sub Pan2()
  'パン2を処理するコード
End Sub

Sub Pan3()
  'パン3を処理するコード
End Sub

さて、ここまでくると気づくでしょう。
・「パン1」専用のコード
・「パン2」専用のコード
・「パン3」専用のコード
このコードは一部をのぞいてほとんど同じコードだということが。
その一部をパラメータに変更してコードを共通化します。
 
そしてこれをメインから呼び出します。
Sub main()
  Call Pan "パン1"
  Call Pan "パン2"
  Call Pan "パン3"
End Sub

Sub Pan(strPan as String)
  'パンを処理するコード
End Sub

あとは Forループに変更。
Sub main()
  Dim strPan(0 to 2)
  strPan(0) = "パン1"
  strPan(0) = "パン2"
  strPan(0) = "パン3"
  For I = 0 to 2
    Call Pan strPan(I)
  Next
End Sub

Sub Pan(strPan as String)
  'パンを処理するコード
End Sub

 

回答
投稿日時: 19/08/14 09:11:29
投稿者: simple

質問者さんが書かれた方針どおりに、とりあえずご自分でコーディングすることを
お薦めします。
 
1)各マシンの性能差による適用順序は考慮せず、マシンA,B,Cの順に適用
2)製品も事前に所要消費時間の降順にソートされているものとする。適用順序は考慮しない。
という前提で良いのではないかと思います。
単にコーディング方法に絞った課題ではないかと思います。
 
余談:
MMYSさん
 Call Pan "パン1"
と言う書き方は
 Call Pan("パン1")
としないといけないのではないですか?
もっとも、擬似コードということであれば良いわけですが。

回答
投稿日時: 19/08/14 22:50:58
投稿者: MMYS

simple さんの引用:

 Call Pan "パン1"
と言う書き方は
 Call Pan("パン1")
としないといけないのではないですか?

そのとおりです。
ご指摘ありがとうございます。
 
まぁ、私ならこのようにアルゴリズムを作成すると
一例です。あとは質問者さん次第。
 

回答
投稿日時: 19/08/15 14:05:32
投稿者: simple

質問者さんは自作する積もりはないようですので、
書いておいたものを提示して、(私にとっての)始末をつけておきます。
こちらの時間も制約ありますしね。
 
簡潔かどうかは知らないが、質問内容を素直に書いたらこうなったというものです。
 
シートレイアウト

   A列      B        C       D   E        F        G       H         I
1行         使用可能 結果_使用            マシンA  マシンB マシンC  結果_使用マシン
            時間     時間
2 マシンA   60                  パン1     30      50      50      
3 マシンB   30                  パン2     20      30      30      
4 マシンC   30                  パン3     15      25      25      
5                               パン4     10      20      20      
6                               おにぎり1  9      13      13      
7                               おにぎり2  7      10      10      
8                               おにぎり3  5       7       7       
9                               おにぎり4  3       5       5       
10                              お菓子1     2       3       4       
11                              お菓子2     1       2       3   

 
Sub test()
    Dim k As Long
    
    '「結果_使用マシン」の列(I列)を"NG"で初期化
    For k = 2 To Cells(Rows.Count, "E").End(xlUp).Row
        Cells(k, "I").Value = "NG"
    Next
    
    'A列にある各マシンごとに、適用する製品を決定する
    For k = 2 To Cells(Rows.Count, "A").End(xlUp).Row
        Call do_check(k)
    Next
End Sub

 
'k行目のマシンが対応する製品を決定する
Function do_check(k As Long)
    Dim machine  As String
    Dim c        As Long
    Dim myTime   As Long
    Dim usedTime As Long
    Dim r        As Long
    Dim v        As Long

    machine = Cells(k, "A").Value 'マシン名
    c = k + 4                     'そのマシンの使用時間の列
    myTime = Cells(k, "B").Value  '残存時間
    usedTime = 0                  '消費時間

    For r = 2 To Cells(Rows.Count, c).End(xlUp).Row
        v = Cells(r, c).Value     'その行にある製品の作成所要時間
        If Cells(r, "I").Value = "NG" Then
            If v <= myTime Then
                myTime = myTime - v
                usedTime = usedTime + v

                '「結果_使用マシン」の欄に書き込む
                Cells(r, "I").Value = machine
            End If
        End If
    Next
    Cells(k, "C").Value = usedTime
End Function

トピックに返信