|
こんばんは。
一週間たってしまいましたね・・・。
私も作ったので、よかったら検証してみてください。
まず、標準モジュール(Module1)に
'========================================================
Sub test()
Dim 組合せ
Dim 組み分け数 As Long
組み分け数 = 3
in_array = Array("A", "B", "C", "D", "E", "F", "G", "H")
Call mk_pat_init(UBound(in_array) - LBound(in_array) + 1, 組み分け数)
st = 1
jdx = 1
Do While mk_pat(pat) = 0
組合せ = dist_array(in_array, "", 組み分け数, pat)
Range(Cells(st, 1), Cells(st + UBound(組合せ, 1), 組み分け数)).Value = _
組合せ
st = st + UBound(組合せ, 1) + 1
Loop
End Sub
'=======================================================================
Function dist_array(ByVal in_array, ByVal delimter As String, ByVal 組み分け数 As Long, ByVal patturn, _
Optional ByVal pdx As Long = 0, Optional ByVal nest As Long = 0, Optional ByVal dupmd As Long = 0)
'指定された配列を指定された組み分け数でグループ化する
'グループ化の詳細は、配列Patturnの値による
'input : in_array ----組み分け数配列(1次元配列)
' delimiter---同一グループ内を区切る文字
' 組み分け数---グループ化する数
' patturnグループメンバ数等の情報(2次元配列)
'
'
'output : dist_array 2次元配列 1次元目がメンバ数
' 2次元目がグループ化されたメンバの組合せ
'pdx nest dupmdは、指定不可 内部処理データ
Static dup() As Class1
Static ans()
Static adx As Long
Static c_array()
If nest = 0 Then
menum = 1
d_cnt = UBound(in_array) - LBound(in_array) + 1
With WorksheetFunction
For ll = LBound(patturn) To UBound(patturn)
For jj = 1 To patturn(ll, 1)
menum = menum * .Combin(d_cnt, patturn(ll, 0))
d_cnt = d_cnt - patturn(ll, 0)
Next jj
menum = menum / .Fact(patturn(ll, 1))
Next ll
End With
ReDim ans(menum - 1, 組み分け数 - 1)
ReDim c_array(組み分け数 - 1)
ReDim dup(UBound(in_array))
adx = 0
pdx = 0
If patturn(pdx, 1) > 1 Then
dupmd = 1
Else
dupmd = 0
End If
End If
If patturn(pdx, 1) = 0 Then
If pdx + 1 <= UBound(patturn, 1) Then
pdx = pdx + 1
If patturn(pdx, 1) > 1 Then
dupmd = 1
Else
dupmd = 0
End If
Else
Exit Function
End If
End If
If dupmd >= 1 Then
Set dup(nest) = New Class1
dup(nest).duparray_init UBound(in_array)
End If
patturn(pdx, 1) = patturn(pdx, 1) - 1
myarray1 = combin_list(in_array, patturn(pdx, 0))
For idx = LBound(myarray1, 1) To UBound(myarray1, 1)
ReDim tmp(UBound(myarray1, 2))
For jdx = LBound(myarray1, 2) To UBound(myarray1, 2)
tmp(jdx) = myarray1(idx, jdx)
Next jdx
retcode = 0
If dupmd > 1 Then
For dpx = nest - dupmd + 1 To nest - 1
retcode = dup(dpx).duparray_chk(tmp())
If retcode <> 0 Then Exit For
Next dpx
End If
If retcode = 0 Then
If dupmd >= 1 Then
dup(nest).duparray_put myarray1(idx, 0)
End If
c_array(nest) = Join(tmp(), delimter)
If nest = 組み分け数 - 1 Then
For kdx = LBound(c_array()) To UBound(c_array())
ans(adx, kdx) = c_array(kdx)
Next kdx
adx = adx + 1
End If
myarray2 = except_array(in_array, tmp())
Erase tmp()
Call dist_array(myarray2, delimter, 組み分け数, patturn, pdx, nest + 1, dupmd + 1)
End If
Next idx
If nest = 0 Then
dist_array = ans()
Erase ans()
Erase c_array()
On Error Resume Next
For idx = UBound(dup()) To LBound(dup())
If Not dup(idx) Is Nothing Then
dup(idx).duparray_term
End If
Set dup(idx) = Nothing
Next
Erase dup()
On Error GoTo 0
End If
End Function
'=======================================================================
Function except_array(in_array, exarray()) As Variant
'指定された配列から、指定された配列メンバを除いた配列を返す
'input : in_array 対象の配列(1次元配列)
' exarray() 取り除くメンバを含んだ配列(1次元配列)
'output: except_array -取り除かれた配列
Dim n_array()
Dim jdx As Long
Dim ok As Boolean
For idx = LBound(in_array) To UBound(in_array)
ok = True
For ex = LBound(exarray()) To UBound(exarray())
If in_array(idx) = exarray(ex) Then
ok = False
Exit For
End If
Next ex
If ok = True Then
ReDim Preserve n_array(jdx)
n_array(jdx) = in_array(idx)
jdx = jdx + 1
End If
Next
except_array = n_array()
End Function
'========================================
Function combin_list(総リスト, 抜取り数, Optional ByVal nest As Long = 0, Optional ByVal st As Long = 0)
'組合せリストを作成する
'input :総リスト----組合せリストを作成する元リスト(1次元の配列)
' 抜取り数----組合せ抜取り数
' nest及び、stは、指定不可 内部で使用するパラメータ
'output:combin_list---組合せリスト2次元配列
Static ans()
Static idx() As Long
Static jdx As Long
If nest = 0 Then
jdx = 0
ReDim idx(抜取り数 - 1)
ReDim ans(WorksheetFunction.Combin(UBound(総リスト) - LBound(総リスト) + 1, 抜取り数) - 1, 抜取り数 - 1)
st = LBound(総リスト)
End If
For idx(nest) = st To UBound(総リスト)
If nest < 抜取り数 - 1 Then
Call combin_list(総リスト, 抜取り数, nest + 1, idx(nest) + 1)
Else
For kdx = 0 To 抜取り数 - 1
ans(jdx, kdx) = 総リスト(idx(kdx))
Next kdx
jdx = jdx + 1
End If
Next
If nest = 0 Then
combin_list = ans()
End If
End Function
'*****************************************
'別の標準モジュール(Module2)に
'======================================================================
Private d_ans As Long
Private d_mem() As Long
Private d_idx() As Long
Sub mk_pat_init(ans As Long, num As Long)
'分配パターンを作成する初期化
ReDim d_mem(1 To ans - 1)
ReDim d_idx(1 To num)
For idx = LBound(d_mem()) To UBound(d_mem())
d_mem(idx) = idx
Next
For idx = LBound(d_idx()) To UBound(d_idx())
d_idx(idx) = 1
Next
d_idx(UBound(d_idx())) = 0
d_ans = ans
End Sub
'========================================================================
Function mk_pat(patturn)
'分配パターンを作成する
Dim mk_pat_ok As Long
Dim wkc As Collection
Dim a_num()
mk_pat = 1
Do While mk_pat_ok = 0
mk_pat_ok = 1
For idx = UBound(d_idx()) To LBound(d_idx()) Step -1
If d_idx(idx) + 1 > UBound(d_mem()) Then
d_idx(idx) = 1
Else
mk_pat_ok = 0
d_idx(idx) = d_idx(idx) + 1
Exit For
End If
Next idx
If mk_pat_ok = 0 Then
ok = 0
jdx = 0
wk = d_mem(d_idx(UBound(d_idx())))
For idx = LBound(d_idx()) To UBound(d_idx()) - 1
If d_mem(d_idx(idx)) > d_mem(d_idx(idx + 1)) Then
ok = 1
Exit For
Else
If d_mem(d_idx(idx)) < d_mem(d_idx(idx + 1)) Then jdx = jdx + 1
wk = wk + d_mem(d_idx(idx))
End If
Next idx
If ok = 0 And wk = d_ans Then
Set wkc = New Collection
ReDim a_num(jdx, 1)
jdx = 0
On Error Resume Next
With wkc
For idx = LBound(d_idx()) To UBound(d_idx())
Err.Clear
.Add d_mem(d_idx(idx)), Str(d_mem(d_idx(idx)))
If Err.Number = 0 Then
a_num(jdx, 0) = d_mem(d_idx(idx))
a_num(jdx, 1) = 1
jdx = jdx + 1
Else
a_num(jdx - 1, 1) = a_num(jdx - 1, 1) + 1
End If
Next idx
End With
On Error GoTo 0
patturn = a_num()
mk_pat = 0
Exit Do
Else
mk_pat_ok = 0
End If
End If
Loop
End Function
'******************************************************************
'最後にクラスモジュール(クラス名は、Class1)を
'====================================================================
Private duparray() '重複チェック用配列
Private fdx As Long '配列のポインタ
'=====================================================================
Sub duparray_init(array_num As Long) '重複チェックを初期化
ReDim duparray(array_num)
For idx = LBound(duparray()) To UBound(duparray())
duparray(idx) = ""
Next idx
fdx = 0
End Sub
'================================================================
Sub duparray_term()
'重複チェックの終わり
On Error Resume Next
Erase duparray()
End Sub
'=================================================================
Sub duparray_put(myvalue)
'チェックメンバの追加
Dim menflg As Boolean
menflg = True
For idx = LBound(duparray()) To fdx - 1
If duparray(idx) = myvalue Then
menflg = False
Exit For
End If
Next idx
If menflg = True Then
duparray(fdx) = myvalue
fdx = fdx + 1
End If
End Sub
'==================================================================
Function duparray_chk(myvalue()) As Long
'重複のチェック
'out duparray_chk 0--重複なし 1--重複あり
duparray_chk = 0
For idx = LBound(duparray()) To fdx - 1
For jdx = LBound(myvalue) To UBound(myvalue)
If duparray(idx) = myvalue(jdx) Then
duparray_chk = 1
Exit For
End If
Next jdx
If duparray_chk = 1 Then Exit For
Next idx
End Function
以上です。testを実行してみて下さい。
これ、結構、難しいねえ・・・、もっと簡単だと思ってました。
|
|