Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


10759 / 13646 ツリー ←次へ | 前へ→

【19670】教えてください ゆか 04/11/13(土) 16:49 質問[未読]
【19673】Re:教えてください Kein 04/11/13(土) 20:22 発言[未読]
【19675】Re:教えてください [名前なし] 04/11/13(土) 21:07 発言[未読]
【19678】Re:教えてください ichinose 04/11/14(日) 0:15 発言[未読]
【19679】Re:教えてください ちゃっぴ 04/11/14(日) 11:34 回答[未読]
【19680】Re:教えてください ちゃっぴ 04/11/14(日) 13:56 発言[未読]
【19691】ありがとうございます ゆか 04/11/15(月) 12:06 お礼[未読]
【19710】教えてください ゆか 04/11/15(月) 16:48 質問[未読]
【19946】Re:教えてください hamar 04/11/19(金) 18:39 回答[未読]
【19951】Re:教えてください ちゃっぴ 04/11/19(金) 22:15 回答[未読]
【19953】Re:教えてください ちゃっぴ 04/11/19(金) 22:21 発言[未読]
【19957】Re:教えてください ichinose 04/11/20(土) 0:29 発言[未読]
【19958】Re:教えてください ちゃっぴ 04/11/20(土) 0:33 発言[未読]
【19959】Re:教えてください 追伸 ichinose 04/11/20(土) 1:22 発言[未読]
【20041】ありがとうございました! ゆか 04/11/25(木) 11:42 お礼[未読]

【19670】教えてください
質問  ゆか  - 04/11/13(土) 16:49 -

引用なし
パスワード
   エクセル初心者です。
例えば、A、B、C、D 4つのアルファベットを、二組に分けたものの組み合わせを全て表示させるようなプログラムを作りたいのですが、探してもアイデアが見つかりません。
どなたかわかる方教えてください。

【19673】Re:教えてください
発言  Kein  - 04/11/13(土) 20:22 -

引用なし
パスワード
   A    BCD
B    ACD
C    ABD
D    ABC
AB    CD
AC    BD
AD    BC
BC    AD
BD    AC
CD    AB

の10通りしかないのでは・・?

【19675】Re:教えてください
発言  [名前なし]  - 04/11/13(土) 21:07 -

引用なし
パスワード
   ▼Kein さん:
A    BCD
B    ACD
C    ABD
D    ABC
AB    CD
AC    BD
AD    BC

の7通りでしょ?

【19678】Re:教えてください
発言  ichinose  - 04/11/14(日) 0:15 -

引用なし
パスワード
   ゆか さん、皆さん、こんばんは。


>エクセル初心者です。
>例えば、A、B、C、D 4つのアルファベットを、二組に分けたものの組み合わせを全て表示させるようなプログラムを作りたいのですが、探してもアイデアが見つかりません。
>どなたかわかる方教えてください。
この問題は、組合せリストを作成するアルゴリズムがネックですよね!!
例えば、例題のようにメンバがA、B、C、Dの場合だと
A組 : B組のメンバ数が
 1 : 3
 2 : 2

という組合せがあります。

1:3の場合は、Combin(4,1)=4の組合せ数になりますが、
2:2の場合は、Combin(4,2)/2=3の組合せ数になりますよね?
(Combinについては、ワークシート関数を参照して下さい)
基本的には、総リストから1を選ぶ組合せ、2つを選ぶ組合せのリストを作成し、
残ったメンバがもう一組のメンバと言う事になりますが、

既に投稿されいるように

1:3の場合は、4つから1つを選ぶ組合せリストを作成すると
     残り
A    BCD
B    ACD
C    ABD
D    ABC

でも、2:2の場合は、4つから2つを選ぶ組合せリストを作成すると

4つから2つを選ぶ組合せリストを作成すると
     残り
1 AB    CD
2 AC    BD
3 AD    BC
4 BC    AD
5 BD    AC
6 CD    AB

とダブりが生じるのでここの工夫が必要ですが、これは帰納的な発想をすると、
上記の1(AB)と6(CD)、2と5、3と4 という組を形成できます。

「アイデア」とあったので、全部のコードは載せませんが、
組合せだけ・・・・。
実は、組合せはここのサイトで以前にも質問がありまして、

http://www.vbalab.net/vbaqa/c-board.cgi?cmd=one;no=16249;id=excel

こんな方法でも可能だし、場合によっては、これの方が都合の良い事も有るのですが、
私の勉強も兼ねて別解で作りました。

'============================
Sub test()
Dim 組合せ
組合せ = combin_list(Array("a", "b", "c", "d"), 2)
Range(Cells(1, 1), Cells(UBound(組合せ, 1) - LBound(組合せ, 1) + 1, 2)).Value = 組合せ
End Sub
'========================================
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

これでnCrの組合せリストの作成は可能です。

後は、呼び出し元で、抜取り数が1のとき、2のときの残りのメンバを作成する方法
を上記を参考にして考えてみて下さい。

【19679】Re:教えてください
回答  ちゃっぴ  - 04/11/14(日) 11:34 -

引用なし
パスワード
   こんな感じでいかがでしょう?
bit演算を利用した方法です。

Private strArray() As String

Sub CallGetComb()
  Call GetComb("ABCDE")
End Sub

Sub GetComb(strTarget As String)
  Dim lngLength As Long
  Dim lngDefault As Long
  Dim lngCount As Long
  Dim lngPrim As Long
  Dim lngElse As Long
  Dim i As Long

  lngLength = Len(strTarget)
  '文字列を1文字ごとに配列に格納
  ReDim strArray(1 To lngLength)
  For i = 1 To lngLength
    strArray(i) = Mid$(strTarget, i, 1)
  Next i
  
  '組み合わせ数 算出
  lngDefault = 2 ^ (lngLength) - 1
  lngCount = (lngDefault - 1) \ 2
  
  '組み合わせ取得
  For lngPrim = 1 To lngCount
    lngElse = lngDefault - lngPrim
    Debug.Print strGetPattern(lngPrim) & ":" _
      & strGetPattern(lngElse)
  Next lngPrim
End Sub

'数値を組み合わせ文字列にする関数
Function strGetPattern(ByVal lngTarget As Long) As String
  Dim strBuf As String
  Dim i As Long
  Dim j As Long
  
  Do
    j = 2 ^ i
    If lngTarget < j Then Exit Do
    If lngTarget And j Then
      strBuf = strBuf & strArray(i + 1)
    End If
    i = i + 1
  Loop
  strGetPattern = strBuf
End Function

4つ以上でも取得できると思います。

【19680】Re:教えてください
発言  ちゃっぴ  - 04/11/14(日) 13:56 -

引用なし
パスワード
   簡単に解説しますと・・・

文字列"ABCD"の存在フラグを2進数の数値として算出させてます。

今回は、算出が楽なように[ABCD]を[DCBA]と反転させています。
つまり

[DCBA] [1111] 15
[D A] [1001]  9

こんな感じで表せますので、組み合わせPatternを2進数で表すと

[  ][0000] 0  [DCBA][1111] 15 ・・・なし

[  A][0001] 1  [DCB ][1110] 14
[ B ][0010] 2  [DC A][1101] 13
[ BA][0011] 3  [DC ][1100] 12
[ C ][0100] 4  [D BA][1011] 11
[ C A][0101] 5  [D B ][1010] 10
[ CB ][0110] 6  [D A][1001]  9
[ CBA][0111] 7  [D  ][1000]  8

7 Patternになります。

これは、すべてのbitが真のとき「1111」= 15から、
1を引いて2で割ったもののようですので
(ここら辺、証明をしていないのでちと怪しい・・・)
それをLoopさせて求めています。

とりあえず 3,4,5個の組み合わせまでは正常のようです。

【19691】ありがとうございます
お礼  ゆか  - 04/11/15(月) 12:06 -

引用なし
パスワード
   皆様、たくさんの返信本当にありがとうございました。
丁寧に教えていただき、感謝しています。
過去の書き込みも参考にして、早速これからやってみたいと思います。
ちゃんとチェックしなくてすみません。
どうもありがとうございました。

【19710】教えてください
質問  ゆか  - 04/11/15(月) 16:48 -

引用なし
パスワード
   ABCDE、5文字を2つに分ける組み合わせについてはわかり、
これを ABCDEFGH の8文字を2つ、3つ、4つ・・・7つのグループに
分けれるように変更したいんです。
8文字を2つにするのはできたのですが、3つからはもうわかりません。。。
これをもし、3つ、4つ、5つ・・・7つと分けるようにするには、
どうしたら良いでしょうか。
もしよろしければ教えていただけないでしょうか。

【19946】Re:教えてください
回答  hamar  - 04/11/19(金) 18:39 -

引用なし
パスワード
   こんにちは。
多分あってると思いますが検証してないです。

Sub test()
Dim n As Integer
Dim m As Integer
Dim s As Integer
Dim d As Long
Dim rn As Long
Dim lcheck As Long
Dim quotient As Long
Dim lastrow As Long
Dim check As Long
Dim flag As Boolean

With WorksheetFunction
n = Val(InputBox("n個のアルファベットを"))
m = Val(InputBox("m個のグループに分ける"))

rn = .Power(m, n - m) * .Fact(m)  '考慮する組み合わせ数

Dim myarray() As Variant
ReDim Preserve myarray(1 To rn, 1 To n)
Application.ScreenUpdating = False
Cells.Clear

For i = 1 To n   '組み合わせ作成
  s = 0
  count = 0
  If i < m Then
    For j = 1 To rn
      lcheck = rn \ .Fact(i)
      If count < lcheck Then
        myarray(j, i) = s
      Else
        If s < i - 1 Then
          s = s + 1
        Else
          s = 0
        End If
        count = 0
      End If
      count = count + 1
    Next
  Else
    For j = 1 To rn
      lcheck = .Power(m, n - i)
      If count < lcheck Then
        myarray(j, i) = s
      Else
        If s < m - 1 Then
          s = s + 1
        Else
          s = 0
        End If
        myarray(j, i) = s
        count = 0
      End If
      count = count + 1
    Next
  End If
Next

d = 0    '要素数0のグループがない組み合わせのみ取り出す
For j = 1 To rn
  flag = True
  For k = 1 To m - 1
    count = 0
    For i = 1 To n
      If myarray(j, i) = k Then count = count + 1
    Next
    If count = 0 Then flag = False
  Next
  If flag = True Then
    For i = 1 To n
      Cells(j, i).Offset(-d, 0).Value = myarray(j, i)
    Next
  Else
    d = d + 1
  End If
Next

For i = 1 To rn - d   'ダブリチェック用の数字を割り当てる
  check = 0
  For j = 1 To n
    s = Cells(i, j).Value
    If s <> 0 Then
      check = check + .Power(2, n - j) * _
      .Power(m, .CountIf(Rows(i), s) - 1)
    End If
  Next
  Cells(i, n + 1).Value = check
Next

For i = rn - d To 1 Step -1   'ダブリ削除
  If .CountIf(Columns(n + 1), Cells(i, n + 1).Value) > 1 Then
    Rows(i).Delete xlShiftUp
  End If
Next

lastrow = Range("A65536").End(xlUp).Row   '結果
For i = 1 To lastrow
  For j = 1 To n
    Cells(i, n + 3).Offset(0, Cells(i, j).Value).Value = _
    Cells(i, n + 3).Offset(0, Cells(i, j).Value).Value + Chr(64 + j)
  Next
Next

Application.ScreenUpdating = True
End With
End Sub

【19951】Re:教えてください
回答  ちゃっぴ  - 04/11/19(金) 22:15 -

引用なし
パスワード
   一応作りましたが、ものすごく遅いです・・・

Private strArray()     As String
Private colCombins     As Collection
Private lngPatterns()    As Long
Private lngLength      As Long
Private lngDiv       As Long

Sub CallGetCombin()
  Call PS_GetCombin("ABCDEFGH", 4)
End Sub

Public Sub PS_GetCombin(ByRef strTarget As String, _
            ByVal lngDivide As Long)
            
  Dim vntCombin    As Variant
  Dim strPatterns()  As String
  Dim strCombin()   As String
  Dim lngCount    As Long
  Dim lngDefault   As Long
  Dim i As Long, j As Long, t As Currency
  
  t = Timer
  lngLength = Len(strTarget) - 1&
  lngDiv = lngDivide - 1
  If lngLength < lngDiv Or lngLength > 30& Then
    Debug.Print "Error"
    Exit Sub
  End If
  
  lngDefault = 2& ^ (lngLength + 1&) - 1&
  ReDim lngPatterns(lngDiv)
  ReDim strPatterns(lngDiv)
  Set colCombins = New Collection
  
  '文字列を1文字ごとに配列に格納
  Call MS_DevideStrings(strTarget)
  
  '組み合わせ取得
  Call MS_GetPattern(lngDefault, 0&, 0&, 0&)
  lngCount = colCombins.Count
  ReDim strCombin(1& To lngCount, 1& To 1&)
  
  For Each vntCombin In colCombins
    j = j + 1
    For i = 0 To lngDiv
      strPatterns(i) = MF_strConvString(vntCombin(i))
    Next i
    strCombin(j, 1) = Join(strPatterns, ":")
  Next vntCombin
  Cells(1&, 1&).Resize(lngCount) = strCombin
  Debug.Print Timer - t
End Sub

'文字列を1文字ごとに配列に格納
Private Sub MS_DevideStrings(ByRef strTarget As String)
  Dim i As Long
  
  ReDim strArray(0 To lngLength)
  For i = 0 To lngLength
    strArray(lngLength - i) = Mid$(strTarget, i + 1, 1)
  Next i
End Sub

'組み合わせ作成
Private Sub MS_GetPattern(ByVal lngBase As Long, _
            ByVal lngPattern As Long, _
            ByVal lngBitCount As Long, _
            ByVal lngDivCount As Long)
            
  Dim lngBit As Long
  Dim i As Long, j As Long
  
  'これ以上分割できない場合
  If lngDiv - lngDivCount = 0& Then
    lngPatterns(lngDivCount) = lngBase
    Call MS_StorePattern
    Exit Sub
  End If
  
  For i = lngLength To 0& Step -1
    lngBit = 2& ^ i
    '有効なbitの場合
    If lngBase And lngBit Then
      lngPatterns(lngDivCount) = lngPattern Or lngBit
      '次の分割に進む
      Call MS_GetPattern(lngBase - lngBit, 0&, _
        lngBitCount + 1&, lngDivCount + 1&)
        
      'bitに余裕がある場合
      If lngLength - lngBitCount - lngDiv + lngDivCount > 1& Then
        'bitを加算
        Call MS_GetPattern(lngBase - lngBit, _
          lngPatterns(lngDivCount), lngBitCount + 1&, _
          lngDivCount)
      End If
    End If
  Next i
End Sub


'降順Bubble Sort
Private Sub MS_DownBubbleSort(ByRef lngArray() As Long)
  Dim lngBuf As Long
  Dim i As Long, j As Long

  Do While j < lngDiv
    i = j + 1
    Do While i < lngDiv + 1
      If lngArray(j) < lngArray(i) Then
        lngBuf = lngArray(j)
        lngArray(j) = lngArray(i)
        lngArray(i) = lngBuf
      End If
      i = i + 1
    Loop
    j = j + 1
  Loop
End Sub

'重複をチェックして重複していなければCollectionに格納
Private Sub MS_StorePattern()
  Dim strPrefix    As String
  Dim lngCurrent()  As Long
  Dim lngBuf()    As Long
  Dim lngFlg     As Long
  Dim blnFlg     As Boolean
  Dim i As Long, j As Long, k As Long
  
  ReDim lngCurrent(lngDiv)
  For j = 0 To lngDiv
    lngCurrent(j) = lngPatterns(j)
  Next j
  
  Call MS_DownBubbleSort(lngCurrent)
  strPrefix = lngCurrent(0) & "@"
  If colCombins.Count <> 0 Then
    Do
      On Error Resume Next
      lngBuf = colCombins(strPrefix & i)
      If Err Then Exit Do
      On Error GoTo 0
      For j = 0 To lngDiv
        If lngBuf(j) = lngCurrent(j) Then
          lngFlg = lngFlg + 1
        Else: Exit For
        End If
      Next j
      If lngFlg = lngDiv + 1 Then blnFlg = True: Exit Do
      lngFlg = 0
      i = i + 1
    Loop
  End If
  If Not blnFlg Then
    Do
      On Error Resume Next
      colCombins.Add lngCurrent, strPrefix & i
      i = i + 1
    Loop While Err
  End If
End Sub

'数値を組み合わせ文字列にする関数
Private Function MF_strConvString(ByVal lngTarget As Long) As String
  Dim i As Long, j As Long, k As Long
   
  Do
    j = 2 ^ i
    If lngTarget < j Then Exit Do
    If lngTarget And j Then
      MF_strConvString = strArray(i) & MF_strConvString
    End If
    i = i + 1
  Loop
End Function

【19953】Re:教えてください
発言  ちゃっぴ  - 04/11/19(金) 22:21 -

引用なし
パスワード
   こんな感じのLogicは浮かびましたが、Codingでこけたので実装していません。

たとえば「ABCDEFGH」という要素があるとして、
最初のbitを常にセットして再帰Loopしてやる

こうすれば大幅な高速化が望めると思います。

日本語で書くとこんな感じになります。

たとえば、一回目は「A」のbitをSetしてやる

要素を加算
再帰ループ

たとえば、1個目の要素にABCをSETしたとして、

DのbitをOnした上で再帰ループ

【19957】Re:教えてください
発言  ichinose  - 04/11/20(土) 0:29 -

引用なし
パスワード
   こんばんは。
一週間たってしまいましたね・・・。
私も作ったので、よかったら検証してみてください。
まず、標準モジュール(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を実行してみて下さい。
これ、結構、難しいねえ・・・、もっと簡単だと思ってました。

【19958】Re:教えてください
発言  ちゃっぴ  - 04/11/20(土) 0:33 -

引用なし
パスワード
   ▼ichinose さん:
>こんばんは。
>一週間たってしまいましたね・・・。
>以上です。testを実行してみて下さい。
>これ、結構、難しいねえ・・・、もっと簡単だと思ってました。

同感です。
シナプスが1万本焼ききれた気が・・・

【19959】Re:教えてください 追伸
発言  ichinose  - 04/11/20(土) 1:22 -

引用なし
パスワード
   ▼ichinose さん:
>こんばんは。
>一週間たってしまいましたね・・・。
>私も作ったので、よかったら検証してみてください。
>まず、標準モジュール(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
patturnという2次元配列の説明です。
一回で投稿できませんでした。

'     patturnグループメンバ数等の情報(2次元配列)
'
'     例1 Array("a", "b", "c", "d", "e", "f", "g", "h")を
'     1,3,4の3グループに分ける場合、
'     dim pat(2,1)
'     メンバ数  メンバ数の重複回数
'     pat(0,0)=1  pat(0,1)=1
'     pat(1,0)=3  pat(1,1)=1
'     pat(2,0)=4  pat(2,1)=1
'      組み分け数 = 3
'      組合せ = _
       dist_array(Array("a", "b", "c", "d", "e", "f", "g", "h"),"**", 組み分け数, pat())
'
'
'     例2 Array("a", "b", "c", "d", "e", "f", "g", "h")を
'     3,3,2の3グループに分ける場合、
'     dim pat(1,1)
'     メンバ数  メンバ数の重複回数
'     pat(0,0)=3  pat(0,1)=2
'     pat(1,0)=2  pat(1,1)=1
'      組み分け数 = 3
'      組合せ = _
       dist_array(Array("a", "b", "c", "d", "e", "f", "g", "h"),"**", 組み分け数, pat())
'
'     例3 Array("a", "b", "c", "d", "e", "f", "g", "h")を
'     2,2,2,2の4グループに分ける場合、
'     dim pat(0,1)
'     メンバ数  メンバ数の重複回数
'     pat(0,0)=2  pat(0,1)=4
'      組み分け数 = 4
'      組合せ = _
       dist_array(Array("a", "b", "c", "d", "e", "f", "g", "h"), "**",組み分け数, pat())

【20041】ありがとうございました!
お礼  ゆか  - 04/11/25(木) 11:42 -

引用なし
パスワード
   返事が遅くなってすみません!!
たくさんのご回答、どうもありがとうございました(> <)
こんなにたくさん丁寧に回答いただけて、本当に助かりました!
がんばります!!
ありがとうございました。

10759 / 13646 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free