質問: vba 組み合わせパターン表示 1,2,3,--,n-1,nからm個とる組み合わせのパターンを セル(1,1)から(ncm、ncm)に表示させる処理をvbaで記述 したいのですが、どうすればいいのでしょうか。 よろしくお願いします。
回答: 再帰呼び出しのアルゴリズムは「自分自身を呼び出す」わけですから、普通の上から下へ 読んでいくフローとはひと味違って、考えにくいところがあります(実は私もしばらくや ってなかったので今回少し手こずりました)。 各行の意味を書きます。 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」の部分の意味です。 テキストベースのみの説明なので伝えにくいのですが、不明な点があったら補足説明しますの で、またおたずねください。