• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:ExcelのVBAで高速に組換え処理がしたい)

ExcelのVBAで高速に組換え処理ができる方法

このQ&Aのポイント
  • ExcelのVBAを使用して、スケジュールの組み合わせを効率的に導き出すプログラムを作成する方法について説明します。
  • 数値を一列に並べて、複数のコースが被らないように4行分組み替える方法を解説します。
  • コース番号には制限がなく、7のコースGは配置の制約がありますが、その他のコースは隣接して配置されます。

質問者が選んだベストアンサー

  • ベストアンサー
  • nag0720
  • ベストアンサー率58% (1093/1860)
回答No.5

すでに回答が出ていますが、別の方法を。 #4のコードは条件に合う組み合わせをランダムに調べる方法ですが、 このコードは、条件に合う組み合わせを重複なく順々に表示します。 Sub 組み合わせ() Dim i As Integer, j As Integer, k As Integer Dim n As Long, m As Long, Cnt As Long Dim S0(6) As Byte, SW(6) As Byte Dim S(3599, 14) As Byte Dim SS(120000, 1) As Integer Dim IsOK As Boolean Dim ii As Integer, jj As Integer Dim nn As Long For i = 0 To 6 S0(i) = i + 1 Next n = 0 Do If S0(6) <> 7 Then k = 0 For i = 0 To 6 S(n, k) = S0(i) k = k + 1 If S0(i) <= 4 Or S0(i) = 6 Then S(n, k) = S0(i) k = k + 1 End If If S0(i) <= 3 Then S(n, k) = S0(i) k = k + 1 End If Next n = n + 1 End If For i = 5 To 0 Step -1 If S0(i) < 7 And S0(i) < S0(i + 1) Then For j = i To 6 SW(j) = S0(j) Next For j = i + 1 To 6 S0(j) = SW(7 + i - j) If S0(j) > SW(i) Then S0(i) = S0(j) S0(j) = SW(i) SW(i) = 99 End If Next Exit For End If Next Loop While S0(0) < 7 ActiveSheet.Select Cnt = 0 nn = 0 n = 0 ' MAX 115920 通り For i = 0 To 3599 For j = i + 1 To 3599 IsOK = True For k = 0 To 14 If S(i, k) = 7 Then IsOK = (S(j, k) = 7) Else IsOK = (S(i, k) <> S(j, k)) End If If Not IsOK Then Exit For Next If IsOK Then SS(n, 0) = i SS(n, 1) = j If S(i, 0) > S(SS(nn, 0), 0) Then nn = n End If n = n + 1 For m = 0 To nn - 1 ii = SS(m, 0) jj = SS(m, 1) IsOK = True For k = 0 To 14 IsOK = (S(ii, k) <> S(i, k) And S(ii, k) <> S(j, k) And S(jj, k) <> S(i, k) And S(jj, k) <> S(j, k)) If Not IsOK Then Exit For Next If IsOK Then For k = 0 To 14 Cells(Cnt * 5 + 1, k + 1) = S(ii, k) Cells(Cnt * 5 + 2, k + 1) = S(jj, k) Cells(Cnt * 5 + 3, k + 1) = S(i, k) Cells(Cnt * 5 + 4, k + 1) = S(j, k) Next Cells(Cnt * 5 + 4, 1).Select Cnt = Cnt + 1 If MsgBox("続行しますか?", 1) = vbCancel Then Exit Sub End If Next End If Next Next End Sub

pcwk
質問者

お礼

ありがとうございます。 コードも書いて頂き非常に助かります。 気になったのですが、1行目の頭と3行目の頭が毎回111と222になっておりますが、 試行回数を増やしていくと最終的に他の数値に変わっていくのでしょうか。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (5)

  • nag0720
  • ベストアンサー率58% (1093/1860)
回答No.6

>気になったのですが、1行目の頭と3行目の頭が毎回111と222になっておりますが、 >試行回数を増やしていくと最終的に他の数値に変わっていくのでしょうか。 条件を満たす組み合わせは200万通り以上ありますから、他の数値に変わるのは、かなり後のほうになります。 組み合わせのパターンがランダムに現れるようにしたいなら、#4のほうがいいでしょう。 ただし、#4のコードは重複チェックしていませんので、確率はかなり低いですが前と同じ組み合わせが出てくる可能性がありますので、それだけ注意してください。 #5のコードでは、1行目と2行目を交換したもの、3行目と4行目を交換したもの、 さらに1,2行目と3,4行目を交換したものなどは同じものとみなしていますので、重複して出てくることはありません。 もしそれも違う組み合わせとして数えるなら、組み合わせの数は3000万通り以上になります。

pcwk
質問者

お礼

ありがとうございます。 おかげでやりたかったことが実現致しました。

全文を見る
すると、全ての回答が全文表示されます。
  • ki-aaa
  • ベストアンサー率49% (105/213)
回答No.4

#3の回答者です。よく考えたら、#2の方法が簡単なので、 その方法を書きます。 Sub 総当り() 'この行から Dim i As Long, j As Long, k As Long, n As Long Dim Gyo1 As Long, Gyo2 As Long, Gyo3 As Long, Gyo4 As Long Dim Retu1 As Long, Retu3 As Long Dim 総組合表(0 To 7199, 0 To 14) As Long Dim nnn As Long Dim i1 As Long, i2 As Long, i3 As Long, i4 As Long, i5 As Long, i6 As Long, i7 As Long Dim 引数表(0 To 6) As Long Dim 出力表(0 To 3, 0 To 14) As Long Dim 組合せ As String '**両端が"7"以外のすべての組合せを作る*3600できる*************************** '*パターン 111・222・333・44・5・66・7 *********************************** For i1 = 1 To 6 For i2 = 1 To 7 If i1 <> i2 Then For i3 = 1 To 7 If i1 <> i3 And _ i2 <> i3 Then For i4 = 1 To 7 If i1 <> i4 And _ i2 <> i4 And _ i3 <> i4 Then For i5 = 1 To 7 If i1 <> i5 And _ i2 <> i5 And _ i3 <> i5 And _ i4 <> i5 Then For i6 = 1 To 7 If i1 <> i6 And _ i2 <> i6 And _ i3 <> i6 And _ i4 <> i6 And _ i5 <> i6 Then For i7 = 1 To 6 If i1 <> i7 And _ i2 <> i7 And _ i3 <> i7 And _ i4 <> i7 And _ i5 <> i7 And _ i6 <> i7 Then n = 0 引数表(0) = i1 引数表(1) = i2 引数表(2) = i3 引数表(3) = i4 引数表(4) = i5 引数表(5) = i6 引数表(6) = i7 For i = 0 To 6 Select Case 引数表(i) Case 1, 2, 3 総組合表(nnn, n) = 引数表(i) 総組合表(nnn, n + 1) = 引数表(i) 総組合表(nnn, n + 2) = 引数表(i) n = n + 3 Case 4, 6 総組合表(nnn, n) = 引数表(i) 総組合表(nnn, n + 1) = 引数表(i) n = n + 2 Case 5, 7 総組合表(nnn, n) = 引数表(i) n = n + 1 End Select Next i nnn = nnn + 1 End If Next i7 End If Next i6 End If Next i5 End If Next i4 End If Next i3 End If Next i2 Next i1 For i = 0 To 3599 For j = 0 To 14 総組合表(i + 3600, j) = 総組合表(i, j) Next j Next i Do 組合せ = "できた" '************************一行目**************************** Gyo1 = Int(Rnd * 3600) '0から3599までの乱数 For j = 0 To 14 If 総組合表(Gyo1, j) = 7 Then Retu1 = j Exit For End If Next j '************************二行目***************************** i = Int(Rnd * 3600) '0から3599までの乱数 For Gyo2 = i To i + 3599 If 総組合表(Gyo2, Retu1) = 7 Then For j = 0 To 14 If 総組合表(Gyo1, j) = 総組合表(Gyo2, j) Then If Retu1 <> j Then Exit For End If Next j If j > 14 Then Exit For End If Next Gyo2 If Gyo2 - i > 3599 Then 組合せ = "できず" '************************三行目***************************** i = Int(Rnd * 3600) '0から3599までの乱数 For Gyo3 = i To i + 3599 For j = 0 To 14 If 総組合表(Gyo3, j) = 7 Then Retu3 = j End If If 総組合表(Gyo1, j) = 総組合表(Gyo3, j) Then Exit For If 総組合表(Gyo2, j) = 総組合表(Gyo3, j) Then Exit For Next j If j > 14 Then Exit For Next Gyo3 If Gyo3 - i > 3599 Then 組合せ = "できず" '************************四行目***************************** i = Int(Rnd * 3600) '0から3599までの乱数 For Gyo4 = i To i + 3599 If 総組合表(Gyo4, Retu3) = 7 Then For j = 0 To 14 If 総組合表(Gyo1, j) = 総組合表(Gyo4, j) Then Exit For If 総組合表(Gyo2, j) = 総組合表(Gyo4, j) Then Exit For If 総組合表(Gyo3, j) = 総組合表(Gyo4, j) Then If Retu3 <> j Then Exit For End If Next j If j > 14 Then Exit For End If Next Gyo4 If Gyo4 - i > 3599 Then 組合せ = "できず" '*********************************************************** Loop Until 組合せ = "できた" For j = 0 To 14 出力表(0, j) = 総組合表(Gyo1, j) 出力表(1, j) = 総組合表(Gyo2, j) 出力表(2, j) = 総組合表(Gyo3, j) 出力表(3, j) = 総組合表(Gyo4, j) Next j Range("A" & Rows.Count).End(xlUp).Offset(3, 0).Resize(4, 15).Value = 出力表 End Sub 'この行まで

pcwk
質問者

お礼

ありがとうございます。 教えて頂いたコードで短時間に結果を出力することができました。 おかげでやりたかったことが実現致しました。

全文を見る
すると、全ての回答が全文表示されます。
  • ki-aaa
  • ベストアンサー率49% (105/213)
回答No.3

三日ごとに区切り、組み合わせを限定すればかなり簡略化できます。 たとえば、 1・・・コースA(連続して3日間)  5・・・コースE(1日間) 2・・・コースB(連続して3日間)  6・・・コースF(連続して2日間) 3・・・コースC(連続して3日間)  7・・・コースG(1日間) 4・・・コースD(連続して2日間) 4は、5か7と組み合わせ3日間のとする 6は、5か7と組み合わせ3日間のとする これで良ければ、できますよ。

pcwk
質問者

お礼

ありがとうございます。 処理時間はかなり短縮できそうですね。 コースの受講日数が増減した場合はどうしたらいいのでしょうか。

全文を見る
すると、全ての回答が全文表示されます。
  • nag0720
  • ベストアンサー率58% (1093/1860)
回答No.2

単純に計算すれば、7つのコースの並べ方は、7!=5040通り そのうち、両端がコースGにならない組み合わせは3600通り 時間さえ気にしなければ、 この3600通りから順に4つ選んで条件に合うものだけを出力すればいいでしょう。 高速にということであれば、 コースGが同じ日になる2つの組み合わせを3600×3600の中から選びんでリストを作り、さらにその中から条件に合う2組の組み合わせを調べればかなり時間短縮になるでしょう。

pcwk
質問者

お礼

ありがとうございます。 もしよろしければ、どういうコードになるか教えて頂けないでしょうか。

全文を見る
すると、全ての回答が全文表示されます。
  • DIooggooID
  • ベストアンサー率27% (1730/6405)
回答No.1

> 例外として7のコースBだけは   この "7のコースB" とは、何のことですか? > 同じ日、 違う日  とは 何のことですか?   "日" の要素 は どこに現れているのでしょう???

pcwk
質問者

補足

> この "7のコースB" とは、何のことですか? すみません、7のコースGの間違いです。 > "日" の要素 は どこに現れているのでしょう??? 下記のように並べて左から1日目、2日目…と続き末尾は15日目になります。 【1日目】          【15日目】 1 1 1 2 2 2 3 3 3 4 4 5 6 6 7 よろしくおねがいします。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • エクセルVBAについて

    VBAに関しての質問です。 A列に日付(10行目から) B列にその日の売上が 300行(300日分)入力されてる表があるとします。 C列にその日を含めた過去N日間の最大の売上を表示させたいのです。 例えば 過去5日間なら過去5日間の最大売上げを毎日表示させたいのです 当然この場合は5日間なのでCの13行目までは空白になります。 「N」日はA1セルに任意の日数で入力することによって希望の期間の数値 が表示できるようにしたいのです。 関数を使ってできるのいですが、事情がありましてエクセルのマクロの 繰り返しのプログラムでやりたいのですが VBAに関しては全く素人ですの。どなたかご教授願えませんでしょうか よろしくお願いします。

  • エクセル VBAで色塗りについて教えてください

    VBA初心者です。 例えばB列2行目から下に(1)~(7)までの番号を不規則に入力することにより F列11~17行目に1セルずつ右へ色塗りをしていくにはどうプログラムをかいたらよいでしょうか? 番号によって、色塗りの行と色は決まっています。 (1)→11行目、黄色 (2)→12行目、青色 (3)→13行目、赤色 (4)→14行目、緑色 (5)→15行目、白色 (6)→16行目、黒色 (7)→17行目、茶色 また色塗りはF列からBD列までで終了です。 番号の入力回数の多いものが色塗りを早く終了できることになります。 VBAの本をみながら試行錯誤していましたが、うまくできず… どなたか詳しい方、お力を貸してください。

  • EXCELでVBAをつかったコピーの高速化

    EXCELのVBAで、A1からA1000まで乱数をセルに書き込むと8秒かかるのですが、これを高速化することが可能でしょうか? For 行番号 = 1 To 1000 Cells(行番号, 1).Value = Int((10 * Rnd) + 1) Next セルに書き込まずに、1000個の乱数を発生させると1秒もかからないので、8秒のうちのほとんどの時間は、セルへの書込み時間にとられています。 EXCELで列のコピーをした場合は、セルへの書込み時間が早いので、1000個の乱数の結果をいったんメモリに書き込み、列のコピーのように、セルにコピーができれば、高速化が可能かなと思うのですが、VBAでできるのでしょうか?よろしくお願いします。 For 行番号 = 1 To 1000 Int((10 * Rnd) + 1)をメモリに書込み Next メモリの内容をA1:A1000にコピー

  • エクセルVBA

    A1からE20までの範囲に数字が表示されています。 そしてその表の行ごとの数値の合計をG列に算出して表示させたいのですが どのようにすれば良いのでしょうか。 VBA初心者なので、分かりやすく教えていただけると助かります。 よろしくお願いいたします。

  • エクセルVBAについて

    エクセルVBAについての質問です。A1、B1と順に入力していき、最終 F1列にカーソルがいったときに(F1を空欄のまま)エンターキーを押すと次の行のD2にカーソルが飛ぶ、そしてD2、E2に入力をして、G列にカーソルを動かしエンターキーで次の行のA列にカーソルが移動する、こんな操作をしたいのですが。つまりF列にカーソルがいったらカーソルは次の行のD列に飛び、G列にカーソルがいったら次の行の先頭つまりA列にカーソルが移動するように。VBA初心者でもつくれるかどうか、よろしくお願いします。

  • エクセルVBAについて教えてください。

    エクセル2007を使ったVBAについて2つ質問です。 1つ目の質問は、5列目の右端の数字を2列目の右端に持ってくるため、 Range("B2").End(xlToRight).Next.Select ActiveCell.FormulaR1C1 = Range("A5").End(xlToRight) というVBAを組んだのですが、2列目に空白が入っている場合うまく動かないため動くように したいのですが、どのように組めばいいのかわかりません。 例    A     B     C     D     E     F     G     H     I     J     K 1  2 【数値1】  □    □     □     1     2     3     4     5  3 4 5 【数値2】   6     7     8     9     10 6 ※□は空白 上記の例の場合、5行目の右端である10を2行目の空白を除いた右端である5の隣に持っていきたいです。 2つ目の質問ですが上記例の2列目の両端(1と5)を選択してDeleteする方法がわかりません。 2つの質問についてわかる方おりましたら教えていただけると助かります。 よろしくお願いしします。

  • エクセルVBA/抽出・貼付け

    下記を行いたいのですが、どのようなコードになるのでしょうか? シート001(入力用) (1)A1~A50、B1~B50、C1~C50、D1~D50  に数値、E1~E50に文字列 (2)F1~F50、G1~G50、H1~H50、I1~I50  に数値、J1~J50に文字列 ※空白行混在 シート002(計算用) シート001に作ったコマンドボタン:クリックにより、 シート002を表示させ、A1~E100に、 シート(1)のA1~E50とF1~J50の空白行以外を連続して 反映させたい。並べ替え用など別シートを用いずに、 VBAコード内で処理したい。

  • Excel VBAについて

    VBA初心者です。 社内の様式に合うようなVBAを組みたいのですが。。。 1,様式は表になっており1つのグループに5つの選択肢があり横に5グループ,縦に12グループあります。(例えば1行目にA1.A2.A3.A4.A5|B1.B2.B3.・・・・E3.E4.E5 2行目にF1.F2.F3.F4.F5|G1.G2・・・・12行目にBM1.BM2のような表) 2,シートは2枚あり1枚目のシートで選んだ1グループ1項目に1つだけ○がつく(ダブルクリックで選択し,違う項目を選択すれば前に選んだ項目の○は消える。) 3,1枚目に丸がついた項目が2枚目の任意のセルに表示される(例えば1枚目のシートのAグループのA3を選択すれば2枚目のシートの任意のセルにA3と表示され,取り消し変更された場合は変更後の選択肢のみ表示される) 4,また,選択する項目は変更されないように保護をかけたい。

  • excel vba DATAの日集計

    excel vba DATAの日集計 いつもお世話になっています。 "DATA"シートのセル"D2"の日付を変えると表の数値が変わるようにしています。 その日毎のデータを"集計"シートの日別の表に飛ぶようにしているのですが、 1日分の転記するセル数が多く、Select Caseで31日分のコードを書くと、あまりにも プロシージャーが大きくなります。(Case1からCase31・・・結果分割してますが) FOR NEXT なのかな~、もっと効率のいい書き方がありましたらよろしくお願いします。 例:"集計"シート1日分は、9行となります。それぞれ"DATA"シートからの転記です。"DATA"シートのF5+F10,G5+G10~AC5+AC10までそれぞれの値を"集計"シートのG5からAD5まで、F6+F12,G6+G12~AC6+AC12までそれぞれの値を"集計"シートのG13からAD13までといった具合です (日の9行はそれぞれ決まったある行とある行の加算です、これが31日分の行があります) Sub macro() Dim myrng As Range Dim c As Range Set myrng = Sheets("DATA").Range("D2") For Each c In myrng Select Case c.Value Case 1 '1行目 Sheets("集計").Range("G5").Value = Sheets("DATA").Range("F5") + Sheets("DATA").Range("F10") | | Sheets("集計").Range("AD5").Value = Sheets("DATA").Range("AC5") + Sheets("DATA").Range("AC10") | | '9行目Sheets("集計").Range("G13").Value = Sheets("DATA").Range("F6") + Sheets("DATA").Range("F12") | | Sheets("集計").Range("AD13").Value = Sheets("DATA").Range("AC6") + Sheets("DATA").Range("AC12")

  • エクセルVBAでデータ検索(Win2000,Excel2000)

    エクセルで毎日の業務で手計算している作業をVBAコードかいて試しているのですが、縦と横の検索で行き詰まってしまい質問しました。どうぞよろしくお願いします。 _A__B____C____D__E__F___G___H 1| 2|_______その他_1~3_4~6_7~10_11~20_21~30 3| 3|__項目A___ 0___50__49__46___43__40 4|__項目B___ 0___45__44__39___37__34 5|__項目C___ 0___43__42__34___30__ 28 行 *このデータは現在(B3:V42)にあり今後増える可能性あり *1行目とA列は空白です。 *2行目とB列は対応する項目です。 *3行目は関係ない値が入っています(データをつくる為の値) このようなデータが、"Sheet2"にあると仮定します "Sheet1"のシート上に配置したComboBox(コントロールツールボックスの)に検索値があります。 (ComboBox1 → 数値 , ComboBox2 → 数値 , ComboBox3 → 文字)*リストは"Sheet1"に登録してあります。 TextBox1 ÷ 2 の結果を小数点以下切上げし、これにTextBox2の値をかけたもの(仮にAAAとする)が、2列目のそれぞれのセルの数値範囲に対応し、TextBox3の文字列がB列に対応し、両検索結果の交わったセルの値を返すようにしたい。 例)もしAAAが「8」なら「F列」をみる。TextBox3 の文字列が「項目B」なら「4行目」をみる。この結果、交わったセルは「F4」なので、「F4」にある値「39」を"Sheet1"."A1"に返す。 また、これらコンボボックス(このシートとは別にテキストボックスを使うこともある)にはひとつずつchangeイベントでいきなり別シート("Sheet3")に書くコードが既に書いてあります。このセルから取り出すことも可能です。よろしくお願いします。