1

Below is my code. I would like to achieve the same result by recursive method because the number of nested loops is varying from 2 to max 8.

Sub permutation()

c1 = Array(1, 2)
c2 = Array(3, 4)
c3 = Array(5, 6)
c4 = Array(7, 8)
c5 = Array(9, 10)
c6 = Array(11, 12)
c7 = Array(13, 14)
c8 = Array(15, 16)

With Sheets("Criteria")
    .Cells.Clear
    n = 1
    For a = LBound(c1) To UBound(c1)
        For b = LBound(c2) To UBound(c2)
            For c = LBound(c3) To UBound(c3)
                For d = LBound(c4) To UBound(c4)
                    For e = LBound(c5) To UBound(c5)
                         For f = LBound(c6) To UBound(c6)
                             For g = LBound(c7) To UBound(c7)
                                 For h = LBound(c8) To UBound(c8)

                                Cells(n, 1).Value = c1(a)
                                Cells(n, 2).Value = c2(b)
                                Cells(n, 3).Value = c3(c)
                                Cells(n, 4).Value = c4(d)
                                Cells(n, 5).Value = c5(e)
                                Cells(n, 6).Value = c6(f)
                                Cells(n, 7).Value = c7(g)
                                Cells(n, 8).Value = c8(h)
                                n = n + 1

                                Next h
                            Next g
                        Next f
                    Next e
                Next d
            Next c
        Next b
    Next a
End With
End Sub

Result

I have also found a recursive code sample on the internet but i really don't know how to modify according to my need. Any help would be really great.

Recursive code sample

Sub RecurseMe(a, v, depth)
    If a > depth Then
        PrintV v
        Exit Sub
    End If
    For x = 1 To 4
        v(a) = x
        a = a + 1
        RecurseMe a, v, depth
        a = a - 1
    Next x
End Sub

Sub PrintV(v)
    For J = 1 To UBound(v): Debug.Print v(J) & " ";: Next J
    Debug.Print
End Sub
Sub test()
    Dim v()
    depth = 4 'adjust
    a = 1
    ReDim v(1 To depth)
    RecurseMe a, v, depth
End Sub

Regards

Shan
  • 429
  • 3
  • 14
  • 31
  • 1
    Can you restate your objective? What do you want to do? – Excel Hero Sep 30 '15 at 19:33
  • I would like to set the number of loops as variable. for example in the above example i used 8 loops so output is 2^8=256. but some times i need only 2 for example. so output will be 2x2 matrix. – Shan Sep 30 '15 at 19:41
  • it just fills up data from my array. this array length is variable so all loops runs according to each array length. – Shan Sep 30 '15 at 19:44
  • If you want to get _full outer join_ of different arrays elements you can take a look at this question: [link](http://stackoverflow.com/questions/31472816). There are ranges instead of arrays but it's easy to adapt. No need for recursion. – BrakNicku Sep 30 '15 at 19:47
  • @BradNicku, Great link! I made an answer on that same post. OP should consider a VBA recordset connection to workbook and run a Cartesian Cross Product SQL across all arrays. – Parfait Oct 01 '15 at 02:03

3 Answers3

3

For future readers, OP's needs essentially follows a Cartesian Product, a mathematical operation of all ordered pairs between sets. One can easily run the Cross Join SQL query or specifically a query without any JOIN statements to achieve the resultset. This is also known as the full outer join query.

Some SQL engines like SQL Server use the CROSS JOIN statement with a resultset equal to rows of product of each included query table (e.g., 2*2*2*2*2*2*2*2 = 2^8 = 256).

In MS Access (the database sibling to MS Excel), using tables defined as the 8 arrays of two items, below would be the cross join query. Item field in each Array table carries the pairing (1,2), (3,4), (5,6) ...

SELECT Array1.Item, Array2.Item, Array3.Item, Array4.Item, 
       Array5.Item, Array6.Item, Array7.Item, Array8.Item
FROM Array1, Array2, Array3, Array4, 
     Array5, Array6, Array7, Array8;

Design

SQL Query

Output

Query Output

Excel solution

Because VBA can connect to various SQL engines by associated drivers including Excel's ODBC Jet Driver, a workbook can connect to ranges of worksheets and run the same cross join query:

Sub CrossJoinQuery()

    Dim conn As Object
    Dim rst As Object
    Dim sConn As String, strSQL As String

    Set conn = CreateObject("ADODB.Connection")
    Set rst = CreateObject("ADODB.Recordset")

    sConn = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
               & "DBQ=C:\Path To\Excel\Workbook.xlsx;"
    conn.Open sConn

    strSQL = "SELECT * FROM [ArraySheet1$A1:A3], [ArraySheet2$A1:A3], 
                            [ArraySheet3$A1:A3], [ArraySheet4$A1:A3],
                            [ArraySheet5$A1:A3], [ArraySheet6$A1:A3], 
                            [ArraySheet7$A1:A3], [ArraySheet8$A1:A3]"
    rst.Open strSQL, conn

    Range("A1").CopyFromRecordset rst

    rst.Close
    conn.Close

    Set rst = Nothing
    Set conn = Nothing

End Sub
Parfait
  • 104,375
  • 17
  • 94
  • 125
  • This solution sounds amazingly neat and simple, but can you confirm that `[ArraySheet1$A1:A3]` is **Sheet1!A1:A3**, `[ArraySheet2$A1:A3]` is **Sheet2!A1:A3**. etc? How to modify the `strSQL` to suit different ranges? That is, to build the **strSQL** for generic use? – PatricK Oct 01 '15 at 07:13
  • Also, can this be on the same workbook as in **C:\Path To\Excel\Workbook.xlsx** connecting to **C:\Path To\Excel\Workbook.xlsx**? – PatricK Oct 01 '15 at 07:20
  • @Patrick Yes `ArraySheet` is a named worksheet and you can use different ranges in same worksheet. Unfortunately, as far as I know ODBC workbook connections must be done externally and not on same workbook. – Parfait Oct 01 '15 at 14:56
  • Thanks @Parfait, I will try play around with ranges, hopefully it works for named ranges too! – PatricK Oct 01 '15 at 22:30
2

If you still want the fix to the code to produce the desired outcome.

Sub RecurseMe(a, v, depth, rw)

    If a > depth Then
        rw = rw + 1
        PrintV v, rw
        Exit Sub
    End If
    For x = 1 To 2
        v(a) = x + ((a - 1) * 2)
        a = a + 1
        RecurseMe a, v, depth, rw
        a = a - 1
    Next x
End Sub

Sub PrintV(v, rw)
    For j = 1 To UBound(v)
        ActiveSheet.Cells(rw, j) = v(j) ' & " ";
    Next j
End Sub
Sub test()
    Dim v()
    Dim rw As Long
    rw = 0
    depth = 8 'adjust to adjust the number of columns
    a = 1
    ReDim v(1 To depth)
    RecurseMe a, v, depth, rw
End Sub
Scott Craner
  • 148,073
  • 10
  • 49
  • 81
0

I approached it as a binary problem:

Public Sub Perms(lCyles As Long)

    Dim sBin As String
    Dim i As Long
    Dim j As Long
    Dim n As Long

    With Sheets("Criteria")
        .Cells.Clear
        n = 1
        For i = 0 To 2 ^ lCyles - 1
            sBin = WorksheetFunction.Dec2Bin(i)
            sBin = String(lCyles - Len(sBin), "0") & sBin
            For j = 1 To Len(sBin)
                .Cells(n, j) = IIf(Mid(sBin, j, 1) = "1", j * 2, j * 2 - 1)
            Next j
            n = n + 1
        Next i
    End With

End Sub
Bas Verlaat
  • 842
  • 6
  • 8