Sub generateCombinations()
'c will hold the counts of each factor; cmb will hold a single combination
Dim c(1 To 10), cmb(1 To 10)
'10 counters for 10 loops; it doesn't seem to work with an array; % is short for As Integer
Dim cntr1%, cntr2%, cntr3%, cntr4%, cntr5%, cntr6%, cntr7%, cntr8%, cntr9%, cntr10%
'i1 and i2 are counters; mc is the maximum number of combinations
Dim i1 As Long, i2 As Long, mc As Long
'j is a counter; nf is the number of factors in the sheet (min 2, max 10)
Dim j%, nf%
'DataArray is the input, ResultArray the output, cdArray is the contents from cd (see below),
'Result is 1 element of cdArray after split in 10 elements
Dim DataArray, ResultArray, cdArray, Result
'r is used to check if a possible combination would have just 1 element, so not a valid combination
Dim r As Double
'cd is a dictionary. Dictionaries are very useful if you are looking for unique values.
'Example:
'After cd is initialized with CreateObject("scripting.dictionary") and subsequently, in this sequence:
'cd(1) = "A" will create an entry with key 1 and value "A",
'cd(2) = "B" will create an entry with key 2 and value "B"
'cd(1) = "C" will OVERWRITE cd(1) with value "C"
'In this procedure, cd entries are created with key values equal to a combination of 10 factors (separated by "|")
'So if a cd entry is "created" again with a key that was alreay created, the entry will be overwritten.
'So no need to bother about any duplicates: the dictionary will prevent duplicates.
Dim cd As Object
'Load DataArray with the input and determine the number of factors (nf)
DataArray = Range("A1").CurrentRegion
nf = UBound(DataArray, 2)
'Check for too many factors
If nf > 10 Then
MsgBox "Max 10 factors allowed"
Exit Sub
End If
'Check for not enough factors
If nf < 2 Then
MsgBox "Min 2 factors required"
Exit Sub
End If
'Maximum number of combinations is 2 ^ 3.
'E.g. with 3 factors, 2 ^ 3 = 8 "combinations" are possible: [I]empty[/I], A, B, C, AB, AC, BC, ABC
mc = 2 ^ nf
'Create the dictionary
Set cd = CreateObject("scripting.dictionary")
'Determine the number of elements for each factor
For i1 = 1 To 10
If i1 > nf Then
c(i1) = 0
Else
For i2 = 2 To UBound(DataArray, 1)
If Not IsEmpty(DataArray(i2, i1)) Then c(i1) = c(i1) + 1
Next i2
End If
Next i1
'Loops over the elements of each factor:
For cntr1 = 1 To IIf(c(1) = 0, 1, c(1))
For cntr2 = 1 To IIf(c(2) = 0, 1, c(2))
For cntr3 = 1 To IIf(c(3) = 0, 1, c(3))
For cntr4 = 1 To IIf(c(4) = 0, 1, c(4))
For cntr5 = 1 To IIf(c(5) = 0, 1, c(5))
For cntr6 = 1 To IIf(c(6) = 0, 1, c(6))
For cntr7 = 1 To IIf(c(7) = 0, 1, c(7))
For cntr8 = 1 To IIf(c(8) = 0, 1, c(8))
For cntr9 = 1 To IIf(c(9) = 0, 1, c(9))
For cntr10 = 1 To IIf(c(10) = 0, 1, c(10))
'Now we have a combination of max 10 elements, we can start building combinations using a binary approach
'we start with 3, because 1 and 2 binary are 1 and 10, so only 1 element and invalid combimnations
'3 is 11 binary, so 2 elements
'mc is a power of 2, representing 1 element, so the loop can stop at mc - 1
For j = 3 To mc - 1
'The following will result in a whole number if j is a power of 2: 4 --2, 8 --> 3, 16 --> 4
'In such case it represents an invalid combination of only 1 element (4 = 100; 8 = 1000; 16 = 10000 etcetera)
r = WorksheetFunction.Log(j, 2)
'Initialize cmb to hold the current combination
For i1 = 1 To 10
cmb(i1) = ""
Next i1
'If valid combination, fill cmd with elements according to the binary representation of j
'e.g. j = 3 (11) first 2 elements; j = 4 invalid; j = 5 (101) first and third element, etcetera
'this is verified with If j And 2 ^ n, e.g. if j = 5 (101) then j And 4 (100) is true:
'each bit of 5 (101) is compared with each bit of 4 (100), resulting in 1 as the first bit is 1 for both 4 and 5.
If r <> Int(r) Then
If j And 1 Then cmb(1) = DataArray(cntr1 + 1, 1)
If j And 2 Then cmb(2) = DataArray(cntr2 + 1, 2)
If nf >= 3 Then If j And 2 ^ 2 Then cmb(3) = DataArray(cntr3 + 1, 3)
If nf >= 4 Then If j And 2 ^ 3 Then cmb(4) = DataArray(cntr4 + 1, 4)
If nf >= 5 Then If j And 2 ^ 4 Then cmb(5) = DataArray(cntr5 + 1, 5)
If nf >= 6 Then If j And 2 ^ 5 Then cmb(6) = DataArray(cntr6 + 1, 6)
If nf >= 7 Then If j And 2 ^ 6 Then cmb(7) = DataArray(cntr7 + 1, 7)
If nf >= 8 Then If j And 2 ^ 7 Then cmb(8) = DataArray(cntr8 + 1, 8)
If nf >= 9 Then If j And 2 ^ 8 Then cmb(9) = DataArray(cntr9 + 1, 9)
If nf >= 10 Then If j And 2 ^ 9 Then cmb(10) = DataArray(cntr10 + 1, 10)
'Add dictionary entry with the key consisting of the combination, separated by |
'If key already present, it won't be added. The "= 1" at the end is irrelevant.
cd(cmb(1) & "|" & cmb(2) & "|" & cmb(3) & "|" & cmb(4) & "|" & cmb(5) & "|" & _
cmb(6) & "|" & cmb(7) & "|" & cmb(8) & "|" & cmb(9) & "|" & cmb(10)) = 1
End If
Next j
Next cntr10
Next cntr9
Next cntr8
Next cntr7
Next cntr6
Next cntr5
Next cntr4
Next cntr3
Next cntr2
Next cntr1
'All combinations to cdArray
cdArray = cd.keys
'Format ResultArray with the required dimensions.
'The dictionary and cdArray are zero based, so indices starting at 0
ReDim ResultArray(0 To cd.Count - 1, 0 To 9)
For i1 = 0 To cd.Count - 1
'Split each combination in separate elements:
Result = Split(cdArray(i1), "|")
For i2 = 0 To 9
ResultArray(i1, i2) = Result(i2)
Next i2
Next i1
'Write the results to the worksheet
Range("L2").Resize(cd.Count, 10) = ResultArray
End Sub