- ベストアンサー
vba 組み合わせパターン表示
1,2,3,--,n-1,nからm個とる組み合わせのパターンを セル(1,1)から(nCm、nCm)に表示させる処理をVBAで記述 したいのですが、どうすればいいのでしょうか。 よろしくお願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
再帰呼び出しのアルゴリズムは「自分自身を呼び出す」わけですから、普通の上から下へ 読んでいくフローとはひと味違って、考えにくいところがあります(実は私もしばらくや ってなかったので今回少し手こずりました)。 各行の意味を書きます。 Const nStr As String = "あいうえおかきく" '←n個の文字列 Const m As Integer = 3 '←取り出す個数 Dim n As Integer '←ご質問文のn Dim rStr As String '←m個取り出した文字列を結合したもの Dim mRow As Integer '←エクセル表へ書き出す際の行番号 Dim Nest As Integer '←再帰呼び出しの深さ=rStrの何文字目に取り出すのか '----------------------- Sub combi() n = Len(nStr) 'nStrの文字列長をnに代入 If m > n Then Exit Sub 'nよりmが大きければ終了 rStr = String(m, " ") 'rStrにm個の空白を代入 Cells.ClearContents '書き出す表をクリア mRow = 0 '書き出す行番号0クリア Nest = 0 '再帰呼び出し深さ0クリア combiPr (0) 'サブルーチン combiPr を引数0で呼び出し End Sub '----------------------- Sub combiPr(n1) 'サブルーチン開始 引数はその時点での開始位置(nStrの何文字目まで処理したか) Dim mCol As Integer '←エクセル表へ書き出す際の列番号 For nn = n1 + 1 To n - m + Nest + 1 'nnを開始位置の次の文字から始めて残りの文字数の手前までFor~Nextを繰り返す Nest = Nest + 1 '再帰呼び出しを1カウントアップ Mid(rStr, Nest, 1) = Mid(nStr, nn, 1) 'rStrのNest番目にnStrのnn番目を代入 If Nest = m Then 'rStrに取り出したのがm文字目なら mRow = mRow + 1 'エクセル表の次の行へ For mCol = 1 To m 'rStrの1文字目からm文字目まで書き出す。 Cells(mRow, mCol).Value = Mid(rStr, mCol, 1) Next Else 'そうでなければ、つまり現在の開始位置(=nStrの何文字目まで処理したか)がm個まで達してなければ Call combiPr(nn) '現在の到達位置(nStrの何文字目まで処理したか)にnnをセットしてcombiPrを呼び出す(再帰呼び出し) End If Nest = Nest - 1'再帰呼び出しを1後退 Next End Sub 手順は原始的なものです。 あ~く まで書かれたカードを8枚ならべて3枚抜き出すことを考えればお解りになるで しょうか。 あ を一枚抜き出し、 い を抜き出し2枚目に置きます。 う を抜き出し、3枚目とします。←これを く まで繰り返します。 次に、い を戻して う を新たな2枚目とします。 え を抜き出し、3枚目とします。←これを く まで繰り返します。 の繰り返し・・・・ を行っているわけです。 ポイントは、1枚目を抜き出すのは か までだという点です。 き まで抜き出したら(く までしかないので)3枚目のカードがなくなります。 同様に2枚目は き までしか抜き出してはいけません。 これが「For nn = n1 + 1 To n - m + Nest + 1」の「n - m + Nest + 1」の部分の意味です。 テキストベースのみの説明なので伝えにくいのですが、不明な点があったら補足説明しますの で、またおたずねください。
その他の回答 (3)
- kigoshi
- ベストアンサー率46% (120/260)
> この combiというプロシジャを起動すれば、8個から3個取り出す組み合わせが表示されるはずなんですよね。 そうです。 > しかし、何も表示されません。エラーは何もでませんが。 パラメータとか指摘する必要ありますか。 特にパラメータなど指定する必要はありません。 Excel2002/標準モジュールにて確認しましたが当方の環境では56通りの組合せが表示されます。
お礼
やり直したらうまく表示されました。ご回答どうもありがとうございました。
補足
ソフト動作をシュミレートしておおよそどのような 動きをしているのか、説明くださればありがたい。 変数の定義など combi(0)で0を入れる意味は
- kigoshi
- ベストアンサー率46% (120/260)
再帰(的)呼び出しのアルゴリズムになると思います。 以下のソースでいかがでしょうか。 Const nStr As String = "あいうえおかきく" '←n個の文字列 Const m As Integer = 3 '←取り出す個数 Dim n As Integer Dim rStr As String Dim mRow As Integer Dim Nest As Integer '----------------------- Sub combi() n = Len(nStr) If m > n Then Exit Sub rStr = String(m, " ") Cells.ClearContents mRow = 0 Nest = 0 combiPr (0) End Sub '----------------------- Sub combiPr(n1) Dim mCol As Integer For nn = n1 + 1 To n - m + Nest + 1 Nest = Nest + 1 Mid(rStr, Nest, 1) = Mid(nStr, nn, 1) If Nest = m Then mRow = mRow + 1 For mCol = 1 To m Cells(mRow, mCol).Value = Mid(rStr, mCol, 1) Next Else Call combiPr(nn) End If Nest = Nest - 1 Next End Sub
補足
この combiというプロシジャを起動すれば、8個から3個取り出す組み合わせが表示されるはずなんですよね。 しかし、何も表示されません。エラーは何もでませんが。 パラメータとか指摘する必要ありますか。
- mina5
- ベストアンサー率44% (4/9)
問題は(nCm、nCm)でなく(nCm、m)でしょうね。
お礼
こんなにもていねいな説明にとても感謝します。 おかげでおおよその意味はつかめました。あと数回読み直し納得がいくようにいたします。