从多个集

时间:2017-12-28 05:45:22

标签: excel vba excel-vba math combinations

我对数学方面的知识有限,所以如果我错了,请原谅这些条款。 我需要从多个集合中创建所有可能的组合,并且该集合中包含至少一个项目。

 - SetA: [1, 2, 3, 4, 5, 6, 7] 
 - SetB: [a, b, c, d] 
 - SetC: [!, @, #, $, %]

示例输出:

 - [1,a,!]
 - [1,2,a,c,@]
 - [1,2,3,4,5,6,7,a,b,c,d,!,@,#,$,%]

是否有特定的组合公式,因为我只能提出嵌套循环,我不确定它是否正确。

3 个答案:

答案 0 :(得分:0)

我想我发现我的解决方案请验证。

首先,对于每一组,我创建了所有可能的组合,并使用pascal三角形的总和检查长度,而不使用null或此公式:

  

n!/(r!(n-r)!) - 1

e.g。

SetB:[a,b,c,d] - > [A,B,C,d,AB,AC,AD,BC,BD,CD,ABC,ABD,ACD,BCD,ABCD]

为每组创建所有可能的组合后,我只使用了产品规则

  

[SetA] X [SetB] X [SetC]

导致所有可能的组合:

  • 多件物品
  • 多套
  • 不重复
  • 没有订单

参考:https://www.mathsisfun.com/combinatorics/combinations-permutations-calculator.html

EDIT1:检查每组的组合数量也可以是(2 ^ n)-1,其中n =集合的长度

答案 1 :(得分:0)

@barrycarter很想获得power set。但是,我们不需要拒绝任何东西,因为我们没有获得集合并集的功率集(这将最终效率低下,因为随着集合数量的增加会有很多拒绝)。我们只需获得每组的功率集,然后获得这些功率组的所有组合。下面的子程序适用于任意长度的任意数组。

Sub CreateAllCombs()

Dim ArrayOfPowSets() As Variant, mySet() As Variant, ArrCounter() As Long, myPS As Variant
Dim myCombs() As Variant, nextComb() As Variant, ParentComb() As Variant, ArrMax() As Long
Dim i As Long, j As Long, k As Long, count1 As Long, count2 As Long, CombExist As Boolean
Dim tempCol As Long, myMax As Long, maxRow As Long, totalCombs As Long

   With ActiveSheet
        maxRow = .Cells(.Rows.count, "A").End(xlUp).Row
    End With

   ReDim ArrayOfSets(1 To maxRow, 1 To 1)
   ReDim ArrCounter(1 To maxRow)
   ReDim ArrMax(1 To maxRow)
   myMax = 0

    For i = 1 To maxRow
        With ActiveSheet
            tempCol = .Cells(i, .Columns.count).End(xlToLeft).Column
        End With
        ReDim mySet(1 To tempCol)
        For j = 1 To tempCol: mySet(j) = Cells(i, j): Next j
        myPS = PowerSet(mySet)
        ArrMax(i) = UBound(myPS)
        If ArrMax(i) > myMax Then
            myMax = ArrMax(i)
            ReDim Preserve ArrayOfPowSets(1 To maxRow, 1 To ArrMax(i))
        End If
        For j = 1 To ArrMax(i)
            ArrayOfPowSets(i, j) = myPS(j)
        Next j
        ArrCounter(i) = 1
    Next i

    CombExist = True
    totalCombs = 0

    Do While CombExist
        count1 = 1
        ReDim ParentComb(1 To 1)

        For i = 1 To maxRow - 1
            For j = 1 To UBound(ArrayOfPowSets(i, ArrCounter(i)))
                ReDim Preserve ParentComb(1 To count1)
                ParentComb(count1) = ArrayOfPowSets(i, ArrCounter(i))(j)
                count1 = count1 + 1
            Next j
        Next i

        For i = 1 To ArrMax(maxRow)
            count2 = count1
            nextComb = ParentComb
            For j = 1 To UBound(ArrayOfPowSets(maxRow, i))
                ReDim Preserve nextComb(1 To count2)
                nextComb(count2) = ArrayOfPowSets(maxRow, i)(j)
                count2 = count2 + 1
            Next j
            totalCombs = totalCombs + 1
            ReDim Preserve myCombs(1 To totalCombs)
            myCombs(totalCombs) = nextComb
        Next i

        k = maxRow - 1

        Do While (ArrCounter(k) >= ArrMax(k))
            ArrCounter(k) = 1
            k = k - 1
            If k = 0 Then Exit Do
        Loop

        If k > 0 Then ArrCounter(k) = ArrCounter(k) + 1 Else CombExist = False

    Loop

    Sheets("Sheet2").Select

    For i = 1 To totalCombs
        For j = 1 To UBound(myCombs(i))
            Cells(i, j) = myCombs(i)(j)
        Next j
    Next i

End Sub

我使用了John Coleman编写的功率集函数的略微修改版本here

Function PowerSet(Items As Variant) As Variant

    Dim PS As Variant
    Dim i As Long, j As Long, k As Long, n As Long
    Dim subset() As Variant

    n = UBound(Items)
    ReDim PS(1 To 1 + 2 ^ n - 2)
    For i = 1 To 2 ^ n - 1
        ReDim subset(1 To n)
        k = 0
        For j = 0 To n - 1
            If i And 2 ^ j Then
                k = k + 1
                subset(k) = Items(j + 1)
            End If
        Next j
        ReDim Preserve subset(1 To k)
        PS(i) = subset
    Next i

    PowerSet = PS

End Function

这假定SetA位于第1行,SetB位于第2行,等等。观察:

enter image description here

此外,应警告读者,这可能需要一段时间,因为有超过1400万种可能的组合。

(2^3 - 1) * (2^5 - 1) * (2^16 - 1) = 7 * 31 * 65535 = 14221095

此外,所有组合一般都写到Sheet2

答案 2 :(得分:-1)

您是否尝试过使用嵌套for循环。

Sub Hello()
    MsgBox ("Hello, world!")

    Dim arr1
    arr1 = Array("1", "2", "3")

    Dim arr2
    arr2 = Array("a", "b", "c")

    Dim arr3
    arr3 = Array("!", "@", "$")

    For i = 0 To UBound(arr1)
        For j = 0 To UBound(arr2)
            For k = 0 To UBound(arr3)
                MsgBox (arr1(i) & arr2(j) & arr3(k))
            Next
        Next
    Next
End Sub