Excel formula 从互斥选项生成所有可能的选项组合

Excel formula 从互斥选项生成所有可能的选项组合,excel-formula,vba,excel,Excel Formula,Vba,Excel,我有一个优化问题,需要我测试潜在投资组合的所有潜在选择组合,我还需要能够快速适应以排除某些选择 这必须在Excel中完成 我的消毒示例的规则如下: 我可以选择从3家杂货店中的任何一家买水果 杂货店可能有不同数量的过道和不同的水果组合供选择 我只能从所有的杂货店挑选一种水果(或者根本没有选择) 组合 我的第一道菜不是任何杂货店的水果 在接下来的几天里,我从杂货店的第三走道摘苹果 然后是第二通道的苹果和第三杂货店的苹果 然后是杂货店3号通道1号通道的苹果 然后我从2号杂货店的第2通道摘苹果,从3

我有一个优化问题,需要我测试潜在投资组合的所有潜在选择组合,我还需要能够快速适应以排除某些选择

这必须在Excel中完成

我的消毒示例的规则如下:

  • 我可以选择从3家杂货店中的任何一家买水果
  • 杂货店可能有不同数量的过道和不同的水果组合供选择
  • 我只能从所有的杂货店挑选一种水果(或者根本没有选择)
组合

  • 我的第一道菜不是任何杂货店的水果
  • 在接下来的几天里,我从杂货店的第三走道摘苹果
  • 然后是第二通道的苹果和第三杂货店的苹果
  • 然后是杂货店3号通道1号通道的苹果
  • 然后我从2号杂货店的第2通道摘苹果,从3号杂货店什么也不摘(即从3号杂货店挑选的苹果与组合1等的苹果相同)
  • 然后我从杂货店2号通道摘苹果,从杂货店3号通道摘苹果(即从杂货店3号通道摘的苹果与组合2号通道摘的苹果相同) 等等
  • 所有这些将给我
    7*4*4=112
    可能的组合,包括

    • 杂货商1的7项选择(6项选择+1项不做)
    • 食品商2的4个选择(3个选择+1个不做任何事情)
    • 食品商3的4个选择(3个选择+1个不做任何事情)
    1。无约束问题

    我的实际问题要复杂得多,但基本结构是正确的

    我想做的是使用or方法填充以下所有可用选项:

  • 无约束问题
  • 约束问题(例如,我关闭第2通道,给出45个有效组合)
  • 2。约束问题

    我尝试过的

    我确实用
    MOD\INT
    方法解决了一个最初的问题,即杂货商选项的数量是相同的。这是一个简单的公式,因为模式是可重复的

    如果有一个智能公式解决方案,那么这将是首选,但我对代码持开放态度(这就是我现在尝试的路线)


    在这次专家交流中,我研究了一个非常相似的问题,列举了五种不同类别事物的每一种组合。每类事物的数量各不相同。枚举必须考虑一个类别中没有选择的可能性,以及从该类别中抽取的任何一个选择。

    我处理这个问题的方法是写一个五位数的数字,其中数字中每个位置的可能位数是一个变量

    Sub CombinatrixPlus()
    'Forms all the combinations of at least two subattributes taken from a selection. _
        No more than one subattribute may be taken from any row.
    'Uses variable base counting method
    
    Dim i As Long, ii As Long, j As Long, k As Long, lenSep As Long, _
        m As Long, mCol As Long, mSheet As Long, mRow As Long, _
        N As Long, nBlock As Long, nMax As Long, nWide As Long
    Dim v As Variant, vInputs As Variant, vResults As Variant
    Dim rg As Range, rgDest As Range
    Dim ws As Worksheet
    Dim s As String, sep As String
    
    Application.ScreenUpdating = False
    sep = ", "      'Separator substring between each subattribute in results
    Set ws = Worksheets("Sheet2")   'Put first batch of results in this worksheet
    Set rgDest = ws.[A2]      'Put results starting in this cell
    mSheet = rgDest.Worksheet.Index
    mCol = rgDest.Column
    lenSep = Len(sep)
    Set rg = Selection      'Cells containing the subattributes
    nBlock = 16384          'Maximum number of values in results array
    
    'Clear the previous results
    Application.DisplayAlerts = False
    For i = Worksheets.Count To ws.Index Step -1
        Worksheets(i).Cells.Clear                   'Clear the cells
        If i > ws.Index Then Worksheets(i).Delete   'Delete the sheet
    Next
    Application.DisplayAlerts = True
    
    N = rg.Rows.Count
    nWide = N       'If results lists subattributes in separate cells
    'nWide = 1      'If results lists subattributes as a single string with separators
    ReDim v(N, 1 To 2)
    vInputs = rg.Value
    v(0, 2) = 1
    For i = 1 To N
        v(i, 1) = Application.CountA(rg.Rows(i))
        v(i, 2) = (v(i, 1) + 1) * v(i - 1, 2)
    Next
    nMax = v(N, 2) - 1
    
    
    ReDim vResults(1 To nBlock, 1 To nWide)
    For i = 1 To nMax
        s = ""
        m = 0
        ii = ii + 1
        For j = 1 To N
            k = (i Mod v(j, 2)) \ v(j - 1, 2)
            If k <> 0 Then
                m = m + 1
                If nWide > 1 Then vResults(ii, j) = vInputs(j, k)
                s = s & sep & vInputs(j, k)
            End If
        Next
        s = Mid$(s, lenSep + 1)
        If nWide = 1 Then vResults(ii, 1) = s  'Results in a concatentated string
        If m < 2 Then ii = ii - 1
    
        If ii = nBlock Then
            Application.StatusBar = "Now posting combination " & i & " of " & nMax
            mRow = rgDest.Worksheet.Cells(Rows.Count, mCol).End(xlUp).Row
            If rgDest.Worksheet.Cells(mRow, mCol) <> "" Then mRow = mRow + 1
            If mRow < rgDest.Row Then mRow = rgDest.Row
            If (Rows.Count - mRow) >= nBlock Then
                rgDest.Worksheet.Cells(mRow, mCol).Resize(nBlock, nWide).Value = vResults
            Else
                mSheet = mSheet + 1
                If Worksheets.Count < mSheet Then Worksheets.Add After:=Worksheets(mSheet - 1)
                With ActiveSheet
                    Set rgDest = .Range(rgDest.Address)
                    For j = 1 To N
                        .Columns(j).ColumnWidth = ws.Columns(j).ColumnWidth
                    Next
                    mRow = rgDest.Row
                    .Cells(mRow, mCol).Resize(nBlock, nWide).Value = vResults
                End With
            End If
            ii = 0
            ReDim vResults(1 To nBlock, 1 To nWide)
        End If
    Next
    
    If ii > 0 Then
            Application.StatusBar = "Now posting combination " & i & " of " & nMax
            mRow = rgDest.Worksheet.Cells(Rows.Count, mCol).End(xlUp).Row
            If rgDest.Worksheet.Cells(mRow, mCol) <> "" Then mRow = mRow + 1
            If mRow < rgDest.Row Then mRow = rgDest.Row
            If (Rows.Count - mRow) >= nBlock Then
                rgDest.Worksheet.Cells(mRow, mCol).Resize(nBlock, nWide).Value = vResults
            Else
                mSheet = mSheet + 1
                If Worksheets.Count < mSheet Then Worksheets.Add After:=Worksheets(mSheet - 1)
                With ActiveSheet
                    Set rgDest = .Range(rgDest.Address)
                    For j = 1 To N
                        .Columns(i).ColumnWidth = ws.Columns(j).ColumnWidth
                    Next
                    mRow = rgDest.Row
                    .Cells(mRow, mCol).Resize(nBlock, nWide).Value = vResults
                End With
            End If
        i = rgDest.Worksheet.UsedRange.Rows.Count   'Reset the scrollbar
    End If
    Application.StatusBar = False   'Clear the status bar
    Application.ScreenUpdating = True
    End Sub
    
    Sub-CombinatrixPlus()
    '形成从所选内容中选取的至少两个子属性的所有组合_
    从任何行中提取的子属性不得超过一个。
    '使用可变基数计数方法
    Dim i为长,ii为长,j为长,k为长,lenSep为长_
    m长,mCol长,MSSheet长,mRow长_
    N等长,N块等长,nMax等长,nWide等长
    Dim v作为变量,vInputs作为变量,vResults作为变量
    变暗rg为范围,rgDest为范围
    将ws设置为工作表
    Dim s作为字符串,sep作为字符串
    Application.ScreenUpdating=False
    sep=“,”结果中每个子属性之间的分隔符子字符串
    设置ws=工作表(“Sheet2”)“将第一批结果放入此工作表
    设置rgDest=ws。[A2]”将结果从此单元格中开始
    mSheet=rgDest.Worksheet.Index
    mCol=rgDest.列
    lenSep=Len(sep)
    设置包含子属性的“rg=Selection”单元格
    nBlock=16384'结果数组中的最大值数
    "清除以前的结果,
    Application.DisplayAlerts=False
    对于i=Worksheets.Count到ws.Index步骤-1
    工作表(i).Cells.Clear“清除单元格
    如果i>ws.Index,则工作表(i).Delete'删除工作表
    下一个
    Application.DisplayAlerts=True
    N=rg.Rows.Count
    nWide=N'如果结果在单独的单元格中列出子属性
    “nWide=1”如果结果将子属性列为带分隔符的单个字符串
    雷迪姆v(N,1到2)
    vInputs=rg.值
    v(0,2)=1
    对于i=1到N
    v(i,1)=应用程序计数(rg.行(i))
    v(i,2)=(v(i,1)+1)*v(i-1,2)
    下一个
    nMax=v(N,2)-1
    ReDim vResults(1到nBlock,1到nWide)
    对于i=1到nMax
    s=“”
    m=0
    ii=ii+1
    对于j=1到N
    k=(i模v(j,2))\v(j-1,2)
    如果k0那么
    m=m+1
    如果nWide>1,则vResults(ii,j)=vInputs(j,k)
    s=s&sep&vInputs(j,k)
    如果结束
    下一个
    s=Mid$(s,lenSep+1)
    如果nWide=1,那么vResults(ii,1)=s'将产生一个包含字符串的结果
    如果m<2,则ii=ii-1
    如果ii=nBlock,则
    Application.StatusBar=“Now posting composition”&i&“of”&nMax
    mRow=rgDest.Worksheet.Cells(Rows.Count,mCol).End(xlUp).Row
    如果rgDest.Worksheet.Cells(mRow,mCol)“,则mRow=mRow+1
    如果mRow=nBlock,则
    rgDest.Worksheet.Cells(mRow,mCol).调整大小(nBlock,nWide).值=vResults
    其他的
    mSheet=mSheet+1
    如果Worksheets.Count0,则
    Application.StatusBar=“Now posting composition”&i&“of”&nMax
    mRow=rgDest.Worksheet.Cells(Rows.Count,mCol).End(xlUp).Row
    如果rgDest.Worksheet.Cells(mRow,mCol)“,则