- ベストアンサー
【Excel】 組み合わせ
A B C という行があった場合 A B C A C B B A C B C A C A B C B A というように 組み合わせを出力する マクロを作りたいのですが どのようにすればよいのででしょうか? よろしくお願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
順列のアルゴリズムは、0から自分で考えようとすると微妙にムツカシイ気がします。ただこれ自体有名なものなので、まずはそれに倣って組みながら仕組みを理解していくと良いです。 大まかな考え方は、『最小(または最大)の組み合わせから、1つずつ大きい(または小さい)ものを取り出していき、最後に最大(または最小)のもを取り出す』ような操作を考えます。 VBAでは文字列の大小の比較も出来てしまうのでこのあたりは何も考えなくて大丈夫です。 もう少し具体的にはどうなるかというと、A B Cであれば最小の並びになっていますが、とりあえずは最小の並びを作ります。 ここから、1つ大きい組み合わせを考えますが、ここにちょっとくせがあります。操作は以下の通りです。 1:一番右の値を【基点】にする 2:【基点】と【基点】の1つ左隣の値を比較して、【基点】のほうが大きいかをチェックする 3:2が成り立てば6へ 4:2が成り立たなければ、【基点】を1つ左へ移す 5:【基点】が一番左にきたら終了(これ以上大きいものはない) 6:【基点】の1つ左の値と、【基点】より右(【基点】含む)にある値の内最大のものを、【基点】の1つ左の値と交換する 7:【基点】より右(【基点】含む)にある値で最小の順列を作りこのとおり並び替える 8:2に戻る 微妙に面倒です。ただこの通り組めばできます。 一応組みました。値はA1に書き込んでください。その後はB列に書き出します。A列の値が大きいとめちゃくちゃ時間かかります。 Option Explicit Type cordinate Number As Variant Order As Byte End Type Function get_permutation() Rem データ格納変数:Cordinate型 Dim memory() As cordinate Rem 汎用関数:Cordinate型 Dim dummy As cordinate Rem カウンタ変数 Dim count, check_count, i, j, k As Byte Rem 桁数 Dim num As Byte Dim ans As Variant num = Len(Range("a1").Value) Rem num個分の配列 ReDim memory(num) Dim total_counter, counter As Variant Dim sub_counter As Byte Rem 初期化--ここから---------------------------------- For i = 0 To num - 1 memory(i).Number = Mid(Range("a1").Value, i + 1, 1) memory(i).Order = i + 1 Next Rem 最小の組み合わせに並べ替える For i = 0 To num - 2 For j = 0 To num - 2 If memory(j).Number > memory(j + 1).Number Then dummy = memory(j) memory(j) = memory(j + 1) memory(j + 1) = dummy End If Next Next Rem 最小の組み合わせ出力 For i = 0 To num - 1 ans = ans & memory(i).Number Next Range("b1").Value = ans ans = "" Rem msgbox ans Rem 初期化--ここまで---------------------------------- count = num - 1 counter = 1 Rem 最小の組み合わせから初めて、現在の組み合わせよりも大きくてかつ最も近い組み合わせを検索し、 _ この繰り返しで最大値に至るようにループさせる。 Do While i If memory(count).Number > memory(count - 1).Number Then Rem msgbox count total_counter = total_counter + 1 dummy = memory(count) check_count = count If count <> num - 1 Then For i = count To num - 1 If dummy.Number > memory(i).Number And _ memory(i).Number > memory(count - 1).Number Then dummy = memory(i) check_count = i End If Next memory(check_count) = memory(count - 1) memory(count - 1) = dummy For i = count To num - 2 For j = count To num - 2 If memory(j).Number > memory(j + 1).Number Then dummy = memory(j) memory(j) = memory(j + 1) memory(j + 1) = dummy End If Next Next Else dummy = memory(num - 1) memory(num - 1) = memory(num - 2) memory(num - 2) = dummy End If count = num - 1 ans = "" For i = 0 To num - 1 ans = ans & memory(i).Number Next Range("b1").Offset(total_counter, sub_counter).Value = ans counter = counter + 1 If total_counter > 65534 Then total_counter = 1 sub_counter = sub_counter + 1 End If Else count = count - 1 If count = 0 Then Exit Do End If End If Loop MsgBox counter end function
その他の回答 (3)
- Wendy02
- ベストアンサー率57% (3570/6232)
参考になるかどうかは分かりませんが、ここのサイトで、Visual Basic で、「順列」という語で探してみました。 http://oshiete1.goo.ne.jp/qa2113807.html ↑ これが、よい(ただし、質問自体に無理はあります) http://oshiete1.goo.ne.jp/qa1537159.html (これは意味が少し違いますが、私の書いた内容で、途中までで使えるはずです。別所途で解答したこともありますが、最初のURLの方式と時間比べをして負けてしまいました。)
- Wendy02
- ベストアンサー率57% (3570/6232)
こんにちは。 #1さんに補足ですが、順列は、ここのカテゴリやVBカテゴリでも出ています。私は、以前は公開していたのですが、最近は、この質問の回答は控えるようにしています。これは、パスワード解除のために使用されることもあるからです。 本当に、マクロやVBAを勉強しようという気持ちがあるなら、インターネット検索すれば、入手できるはずで、Q&Aで、そのままお渡しするというのはしておりません。また、#1さんのおっしゃっているのは、順列のアルゴリズムですが、それを扱うレベルは、ひととおり、VBA卒業のレベルで、また、この種のものが分からない場合、必ず、Google検索で、調べてほしいです。ただし、順列で、VBAでは、必ずしも、「再帰」を使うかどうかは、なんとも言えません。単にループでもよいはずです。 また、組み合わせのアルゴリズムは、一部の方が非公開にしているようですので、こちらも基本的には公開はしないようにしております。ご質問は、どうやら順列のようですが。
- Dxak
- ベストアンサー率34% (510/1465)
お答え付きませんね^^; 「組み合わせ」と称しているのは、「順列」と言い、国語辞書だと「組み合せと」逆に位置する言葉になります で、こういうマクロは、再帰アルゴリズムを使用して、「順列の挙列」を行うのですが、考えるのに時間が掛るかなと思ったら・・・ 過去の質問で、いくつか回答が出てますので、「順列 再帰」で検索してみてください
お礼
ありがとうございます。 いろいろと難しそうですね がんばってみます!
お礼
私の検索の仕方が悪かったようです。 検索したのですが、有料のExcelマクロしか見つけられませんでした。 私の欲しいのはあくまでキーワードの順列だったようですね。 見つからないはずですね。 ありがとうございます。