找到组合后在 VBA 中过滤

Posted

技术标签:

【中文标题】找到组合后在 VBA 中过滤【英文标题】:Filtering in VBA after finding combinations 【发布时间】:2012-10-09 02:17:56 【问题描述】:

在这个网站上得到一些帮助后,我现在正在寻找更多。这是我之前的帖子:stacking and layering boxes in excel

我现在可以做出所有可能的组合。但是我的下一步是设置一些参数。我的意思是盒子的高度和重量。如果我要按框名称(A,B,....)将 B 列按重量(kg)和 C 列按高度(毫米)放置在 A 列的“Sheet2”上。然后在“Sheet3”上放置我的最大身高和最大体重。 B2 最大重量为 30 公斤,C3 最大高度为 500 毫米。

我怎样才能让我的宏检查这些参数,如果它们确实适合它们,它们会像我之前的问题一样放在列中,如果它超过我的体重或身高,它不会打扰放置它。

希望很快听到 :) 开始享受 e​​xcel!


编辑:

Box name    Weight  height
A              1    0.12
B              5    0.92
C              3    0.5
D              2    0.34

........等等

这就是我放置输入信息的方式。我想要很多盒子,甚至可能多达 100 个

【问题讨论】:

【参考方案1】:

作为对先前解决方案的增强

输入格式 (请在学习我的代码后实现您自己的输入/输出farmat)

<num of box>   <box name 1>  <box name 2> ... <box name N>
<max height>   <height 1>    <height 2>...  
<max weight>   <weight 1>    <weight 2> ...
<output result 1>
<output result 2>
.
.
.

示例输入和输出

3   A   B   C   D   E
7.7 3   1   1   1   2
5.5 2   1   2   3   3
A                   
B                   
AB                  
C                   
AC                  
BC                  
ABC                 
D                   
AD                  
BD                  
CD                  
E                   
AE                  
BE                  
CE

不限于整数,可以使用浮点数

代码:

 Function stackBox()
    Dim ws As Worksheet
    Dim width As Long
    Dim height As Long
    Dim numOfBox As Long
    Dim optionsA() As Variant
    Dim results() As Variant
    Dim str As String
    Dim outputArray As Variant
    Dim i As Long, j As Long
    Dim currentSymbol As String
    '------------------------------------new part----------------------------------------------
    Dim maxHeight As Double
    Dim maxWeight As Double
    Dim heightarray As Variant
    Dim weightarray As Variant
    Dim totalHeight As Double
    Dim totalWeight As Double
    '------------------------------------new part----------------------------------------------

    Set ws = Worksheets("Sheet1")
    With ws
        'clear last time's output
        height = .Cells(.Rows.Count, 1).End(xlUp).row
        If height > 3 Then
            .Range(.Cells(4, 1), .Cells(height, 1)).ClearContents
        End If

        numOfBox = .Cells(1, 1).Value
        width = .Cells(1, .Columns.Count).End(xlToLeft).Column
        If width < 2 Then
            MsgBox "Error: There's no item, please fill your item in Cell B1,C1,..."
            Exit Function
        End If


        '------------------------------------new part----------------------------------------------
        maxHeight = .Cells(2, 1).Value
        maxWeight = .Cells(3, 1).Value
        ReDim heightarray(1 To 1, 1 To width - 1)
        ReDim weightarray(1 To 1, 1 To width - 1)
        heightarray = .Range(.Cells(2, 2), .Cells(2, width)).Value
        weightarray = .Range(.Cells(3, 2), .Cells(3, width)).Value
        '------------------------------------new part----------------------------------------------

        ReDim optionsA(0 To width - 2)
        For i = 0 To width - 2
            optionsA(i) = .Cells(1, i + 2).Value
        Next i

        GenerateCombinations optionsA, results, numOfBox


        ' copy the result to sheet only once
        ReDim outputArray(1 To UBound(results, 1) - LBound(results, 1) + 1, 1 To 1)
        Count = 0
        For i = LBound(results, 1) To UBound(results, 1)
            If Not IsEmpty(results(i)) Then
                'rowNum = rowNum + 1
                str = ""
                totalHeight = 0#
                totalWeight = 0#
                For j = LBound(results(i), 1) To UBound(results(i), 1)
                    currentSymbol = results(i)(j)

                    str = str & currentSymbol 'results(i)(j) is the SYMBOL e.g. A, B, C

                    'look up box's height and weight , increment the totalHeight/totalWeight
                    updateParam currentSymbol, optionsA, heightarray, weightarray, totalHeight, totalWeight

                Next j
                If totalHeight < maxHeight And totalWeight < maxWeight Then
                    Count = Count + 1
                    outputArray(Count, 1) = str
                End If

            '.Cells(rowNum, 1).Value = str
            End If
        Next i
        .Range(.Cells(4, 1), .Cells(UBound(outputArray, 1) + 3, 1)).Value = outputArray
    End With

End Function

Sub updateParam(ByRef targetSymbol As String, ByRef symbolArray As Variant, ByRef heightarray As Variant, ByRef weightarray As Variant, ByRef totalHeight As Double, ByRef totalWeight As Double)
Dim i As Long
Dim index As Long
index = -1
For i = LBound(symbolArray, 1) To UBound(symbolArray, 1)
    If targetSymbol = symbolArray(i) Then
        index = i
        Exit For
    End If
Next i


If index <> -1 Then
    totalHeight = totalHeight + heightarray(1, index + 1)
    totalWeight = totalWeight + weightarray(1, index + 1)
End If
End Sub

Sub GenerateCombinations(ByRef AllFields() As Variant, _
                                             ByRef Result() As Variant, ByVal numOfBox As Long)

  Dim InxResultCrnt As Integer
  Dim InxField As Integer
  Dim InxResult As Integer
  Dim i As Integer
  Dim NumFields As Integer
  Dim Powers() As Integer
  Dim ResultCrnt() As String

  NumFields = UBound(AllFields) - LBound(AllFields) + 1

  ReDim Result(0 To 2 ^ NumFields - 2)  ' one entry per combination
  ReDim Powers(0 To NumFields - 1)          ' one entry per field name

  ' Generate powers used for extracting bits from InxResult
  For InxField = 0 To NumFields - 1
    Powers(InxField) = 2 ^ InxField
  Next

 For InxResult = 0 To 2 ^ NumFields - 2
    ' Size ResultCrnt to the max number of fields per combination
    ' Build this loop's combination in ResultCrnt

    ReDim ResultCrnt(0 To NumFields - 1)
    InxResultCrnt = -1
    For InxField = 0 To NumFields - 1
      If ((InxResult + 1) And Powers(InxField)) <> 0 Then
        ' This field required in this combination
        InxResultCrnt = InxResultCrnt + 1
        ResultCrnt(InxResultCrnt) = AllFields(InxField)
      End If
    Next

    If InxResultCrnt = 0 Then
        Debug.Print "testing"
    End If
    'additional logic here
    If InxResultCrnt >= numOfBox Then
        Result(InxResult) = Empty

    Else
         ' Discard unused trailing entries
        ReDim Preserve ResultCrnt(0 To InxResultCrnt)
        ' Store this loop's combination in return array
        Result(InxResult) = ResultCrnt
    End If

  Next

End Sub

【讨论】:

为什么我的excel看不到宏运行菜单中的宏?宏正在工作,只是无法选择并将其添加到按钮或其他东西 我还想让这个问题更复杂一点,这是我的新问题:***.com/questions/13151975/… 如果你移动到不同的列,这仍然可以运行在 100 个盒子上吗? 1.如果您想直接调用宏,请将 FUNCTION 更改为 SUB。 2.“向不同的列移动”是什么意思? 如果我尝试使用 100 个盒子,它不起作用。我认为行数一定是有限的,因此我需要向右移动几列才能将它们全部放在一张纸上。

以上是关于找到组合后在 VBA 中过滤的主要内容,如果未能解决你的问题,请参考以下文章

vba中的sql语法错误以过滤组合框

在数据透视 + VBA + 动态解决方案中运行所有可能的页面过滤器组合

VBA过滤后选择可见单元格

为什么Access VBA下拉方法不起作用?

在vba中使用多个字符串过滤访问报告,获取数据类型不匹配

vba access 2010更新过滤子表单