[[20080501151223]] 『組合せ作成』(亜美ちゃん) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『組合せ作成』(亜美ちゃん)
 ABC  ABC ABC の組合せ簡単に作成したいのですがいい方法ありませんでしょうか。 
 INIDRECT関数と&を使ってできそうな気がするのですが・・・
 ちなみにAAA AAB AAC ABA ACA・・・CCC まで作成したいのですがいちいち入力が
 大変ですし、間違いがあるかもしれないのでよろしくお願いいたします。
 例では3つのグループで3*4*3種類なのですが
 実際は4つのグループで40*70*40種類作成しなければならないのです。
 XP-SP2,2003使用です。

 不得意な分野なので、取りあえずご質問の内容だけ確認させてください。

 >例では3つのグループで3*4*3種類なのですが

 何が3つのグループなのですか?
 3*4*3のそれぞれの意味は?

 私には、一つのグループで、3*3*3 (全27種類)に思えるのですが。

 <追記>
 カキコしたあとで、気がついたのですが、

 第1ABC、第2ABC、第3ABC で3つのクループと云うことですか?

 しかし、3*4*3だとすると
 第1はABC、第2はABCD、第3はABC ではないですか?
          ↑
     つまり、ここは"D"では?

 それが正しいとすると、実際は 40*70*40ですから、全112,000種類と云うことになりますか?

 (半平太)

 すみません
 第1はABC、第2はABCD、第3はABC ではないですか
 ご指摘のとおりです。
 実際は 40*70*40ですから、全112,000種類ということです。

 > 実際は 40*70*40ですから、全112,000種類ということです。

 あまりの量に逃げ出し寸前です。取りあえずの案(バージョンは、XL2007を想定しています)。

 1.A、B、C 各列一行目に「1」と入力

 2.式の入力
 (1) A2セル =IF(AND(B1=70,C1=40),A1+1,A1)
 (2) B2セル =IF(C1=40,IF(B1=70,1,B1+1),B1)
  (3) C2セル =MOD(ROW(A2)-1,40)+1

  2行目の式を112,000行目までコピー

  行   _A_  _B_  _C_  
  1     1    1    1  
  2     1    1    2  
  3     1    1    3  
  4     1    1    4  

  (半平太)

 こんな塩梅でどうでせう。(ROUGE)
'----
Sub test()
Dim txt1 As String, txt2 As String, txt3 As String
Dim x, y, z, tbl()
Dim i As Long, ii As Long, iii As Long, n As Long, m As Long
txt1 = Application.InputBox("組み合わせに使用する文字を" & Chr(10) _
    & "「,」区切りで入力してください。", "その1", Type:=2)
txt2 = Application.InputBox("組み合わせに使用する文字を" & Chr(10) _
    & "「,」区切りで入力してください。", "その2", Type:=2)
txt3 = Application.InputBox("組み合わせに使用する文字を" & Chr(10) _
    & "「,」区切りで入力してください。", "その3", Type:=2)
x = Split(Replace(txt1, ",", ","), ",")
y = Split(Replace(txt2, ",", ","), ",")
z = Split(Replace(txt3, ",", ","), ",")
m = 1
ReDim tbl(1 To WorksheetFunction.Min(Rows.Count, (UBound(x) + 1) * (UBound(y) + 1) * (UBound(z) + 1)), 1 To 1)
For i = 0 To UBound(x)
    For ii = 0 To UBound(y)
        For iii = 0 To UBound(z)
            n = n + 1
            If n > Rows.Count Then
                n = 1
                m = m + 1
                ReDim Preserve tbl(1 To UBound(tbl, 1), 1 To UBound(tbl, 2) + 1)
            End If
            tbl(n, m) = x(i) & y(ii) & z(iii)
        Next iii
    Next ii
Next i
Cells.ClearContents
Range("A1").Resize(UBound(tbl, 1), UBound(tbl, 2)).Value = tbl
Erase tbl, x, y, z
End Sub

 新規ブックの標準モジュールに

 '============================================================
 Sub main()
    Dim idx As Long
    Dim g0 As Long
    Dim wk As Variant
    Dim ans() As Variant
'  ↑組み合わせメンバーを取得する配列
    Dim rng As Range
'  ↑組み合わせセル範囲

    Call サンプル作成

    Set rng = Range("a1").CurrentRegion
    Call ttlhit_init(rng.Columns.Count)
    For g0 = 1 To rng.Columns.Count
       With rng.Cells(1, g0)
          Call ttlhit_add(Range(Cells(1, .Column), Cells(Rows.Count, .Column).End(xlUp)))
          End With
       Next
    idx = 10
    ReDim ans(1 To rng.Columns.Count)
    Do While ttlhit_get(ans()) = 0
       wk = ""
       For g0 = LBound(ans()) To UBound(ans())
          wk = wk & ans(g0)
          Next
       Cells(idx, 1).Value = wk
       idx = idx + 1
       Loop
    MsgBox "以上" & idx - 10 & "通り"
    Call ttlhit_term
 End Sub
 '============================================================
 Sub サンプル作成()
    Cells.ClearContents
    Range("a1:d1").Value = [{"a","a","a","a"}]
    Range("a2:d2").Value = [{"b","b","b","b"}]
    Range("a3:d3").Value = [{"c","c","c","c"}]
    Range("d4").Value = "d"
    MsgBox "サンプル作成  セルA10から処理を開始します"
 End Sub

別の標準モジュールに組合せ処理ルーチン

    Private ttl_rng() As Range
    Private ttl_idx() As Long
    Private ttl_a_num As Long
 '===================================================================
 Sub ttlhit_init(hitnum As Long)
 '組合せ処理の開始宣言
 'input : hitnum 抜き取り数
    Dim g0 As Long
    Erase ttl_rng()
    Erase ttl_idx()
    ReDim ttl_rng(1 To hitnum)
    ReDim ttl_idx(1 To hitnum)
    For g0 = LBound(ttl_idx()) To UBound(ttl_idx())
      ttl_idx(g0) = 1
      Next
    ttl_idx(UBound(ttl_idx())) = 0

    ttl_a_num = 0
 End Sub
 '======================================================================
 Sub ttlhit_add(rng As Range)
 '組合せ標本セル範囲の登録
 'input : rng 連続したセル範囲
    Set ttl_rng(ttl_a_num + 1) = rng
    ttl_a_num = ttl_a_num + 1
 End Sub
 '======================================================================
 Function ttlhit_get(ans()) As Long
 '組み合わせメンバーを配列に出力する
 'output: ans() メンバの配列
 '    ttlhit_get:0 -- 正常に配列取得
 '            1 -- メンバの終わり
    Dim g0 As Long
    ttlhit_get = 1
    For g0 = UBound(ttl_idx()) To LBound(ttl_idx()) Step -1
       If ttl_idx(g0) + 1 <= ttl_rng(g0).Count Then
          ttl_idx(g0) = ttl_idx(g0) + 1
          ttlhit_get = 0
          Exit For
       Else
          ttl_idx(g0) = 1
          End If
       Next
    If ttlhit_get = 0 Then
       For g0 = LBound(ttl_idx()) To UBound(ttl_idx())
          ans(g0) = ttl_rng(g0).Cells(ttl_idx(g0)).Value
          Next
       End If
 End Function
 '======================================================================
 Sub ttlhit_term()
 '組合せ処理に終了
    Erase ttl_rng()
    Erase ttl_idx()
    ttl_a_num = 0
 End Sub

 予め組合せ処理部分を再利用可能にしておくと
 同じような事象に対応できると思いますよ!!
 (私は、よくクラス化(オブジェクト)して利用しています)
 尚、列が増えてもコードの変更は殆ど要らないと思います。

 ichinose

 これは一体何のデータでっしゃろ?
 スポーツでは無いみたいやし、薬品混合の臨床データ? それとも金属強度テストの
 データ?
 ま、それはともかく、Sheet2でグループ分けしたデータをSheet1に標本別に取り出す
 マクロをROUGEせんぱいの工法をパクリながら作成してみました。
 Sheet2のデータをこんな塩梅に並べて実行しませう。
 	A	 B	   C	    D	       E
 1	Aグループ	 Bグループ Cグループ Dグループ Eグループ
 2	標本A1	 100g	   C1	    D1	      E1
 3	標本A2	 120g	   C2	    D2	      E2
 4	標本A3	 130g	   C3	    D3	      E3
 5       ...        ...       ...       ...        ...
 6       ...        ...       ...       ...        ...
 7       ...        ...       ...       ...        ...
 8       ...        ...       ...       ...        ...
 .       ...        ...       ...       ...        ...
 .
 .
           (弥太郎)
 '--------------------------
 Sub Get組合せ()
    Dim i As Long, n As Long, m As Integer, Cnt As Long, u As Integer, x(), tbl, y()
    Dim ii As Long, iii As Long, iiii As Long, iiiii As Long, b As Integer
    With Sheets("sheet2")
        b = StrConv(InputBox("グループ数はなんぼでっか?"), vbNarrow)
        tbl = .Cells(2, 1).Resize(.Range("a:" & Chr(64 + b)). _
                    Cells.Find("*", , , , xlByRows, xlPrevious).Row - 1, b)
    End With
    For u = 1 To b
        For i = 1 To UBound(tbl, 1)
            If Not IsEmpty(tbl(i, u)) Then
                ReDim Preserve y(i - 1)
                y(i - 1) = tbl(i, u)
            End If
        Next i
        ReDim Preserve x(u - 1)
        x(u - 1) = y
        If u > 2 Then Cnt = IIf(Cnt = 0, (UBound(x(u - 2)) + 1) * (UBound(x(u - 1)) + 1), _
                        Cnt * (UBound(x(u - 1)) + 1))
    Next u
    Application.ScreenUpdating = False
    ReDim tbl(1 To IIf(Cnt > 60000, 60000, Cnt), 1 To UBound(x) + 1)
    With Sheets("sheet1")
        .Cells.ClearContents
        For i = 0 To UBound(x(0))
            For ii = 0 To UBound(x(1))
                For iii = 0 To UBound(x(2))
                    Select Case u - 1
                        Case 3
                            Call work(u, n, tbl, m, Cnt)
                            For b = 1 To 3
                                tbl(n, b + m) = x(b - 1)(IIf(b = 1, i, IIf(b = 2, ii, iii)))
                            Next b
                        Case 4
                            For iiii = 0 To UBound(x(3))
                                Call work(u, n, tbl, m, Cnt)
                                For b = 1 To 4
                                    tbl(n, b + m) = x(b - 1)(IIf(b = 1, i, IIf(b = 2, ii, _
                                                IIf(b = 3, iii, iiii))))
                                Next b
                            Next iiii
                        Case 5
                            For iiii = 0 To UBound(x(3))
                                For iiiii = 0 To UBound(x(4))
                                    Call work(u, n, tbl, m, Cnt)
                                    For b = 1 To 5
                                        tbl(n, b + m) = x(b - 1)(IIf(b = 1, i, IIf(b = 2, ii, _
                                                IIf(b = 3, iii, IIf(b = 4, iiii, iiiii)))))
                                    Next b
                                Next iiiii
                            Next iiii
                    End Select
                Next iii
            Next ii
        Next i
        .Cells(1, 1).Offset(, m).Resize(, u - 1) = Sheets("sheet2").Cells(1, 1).Resize(, u - 1).Value
        .Cells(2, 1).Resize(UBound(tbl, 1), UBound(tbl, 2)) = tbl
    End With
    Application.ScreenUpdating = True
End Sub
Sub work(u, n, tbl, m, Cnt)
    n = n + 1
    If n > UBound(tbl, 1) Then
        With Sheets("sheet1")
            .Cells(1, 1).Offset(, m).Resize(, u - 1) = Sheets("sheet2").Cells(1, 1).Resize(, u - 1).Value
            n = 1
            m = m + u
            ReDim Preserve tbl(1 To UBound(tbl, 1), 1 To UBound(tbl, 2) + u)
        End With
    End If
 End Sub


 ちょとしゅうせぇ^^
      (弥太郎)5/7 10:04


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.