背景:我将数据库中的所有字段名称都拉到了一个数组中 - 我已经完成了这个部分没有问题,所以我已经有一个包含所有字段的数组(allfields())而且我有计算了多少个字段(numfields)。
我现在正在尝试编译可以从各种字段名称中创建的所有唯一组合。例如,如果我的三个字段是NAME,DESCR,DATE,我想返回以下内容:
我为此尝试了一些不同的东西,包括多个嵌套循环,并在这里修改答案:How to make all possible sum combinations from array elements in VB以满足我的需求,但似乎我无法访问必要的库(我的工作PC上有System或System.Collections.Generic),因为它只有VBA。
有没有人有一些可以实现此目的的VB代码?
非常感谢!
答案 0 :(得分:6)
我将假设基于单一的数组,因为它使得解释更容易。由于VBA支持基于一个阵列,所以这应该没问题,尽管如果这是你想要的,它可以轻松调整到基于零的数组。
AllFields(1 To NumFields)包含名称。
有一个循环:对于Inx = 1到2 ^ NumFields - 1
在循环内,将Inx视为二进制数,其编号为1到NumFields。对于1和NumField之间的每个N,如果位N是1,则包含此组合中的AllFields(N)。
此循环生成2 ^ NumFields - 1种组合:
Names: A B C
Inx: 001 010 011 100 101 110 111
CombinationS: C B BC A A C AB ABC
VBA唯一的难点是获得Bit N的值。
额外部分
由于每个人都在实施我的算法,我觉得我最好先说明我会怎么做。
我已经用一组令人讨厌的字段名填充了一组测试数据,因为我们还没有被告知名字中可能包含哪些字符。
子程序GenerateCombinations开展业务。我是递归的粉丝,但我不认为我的算法很复杂,足以证明它在这种情况下的使用。我将结果返回到锯齿状数组中,我更喜欢连接。 GenerateCombinations的输出将输出到即时窗口以演示其输出。
Option Explicit
此例程演示了GenerateCombinations
Sub Test()
Dim InxComb As Integer
Dim InxResult As Integer
Dim TestData() As Variant
Dim Result() As Variant
TestData = Array("A A", "B,B", "C|C", "D;D", "E:E", "F.F", "G/G")
Call GenerateCombinations(TestData, Result)
For InxResult = 0 To UBound(Result)
Debug.Print Right(" " & InxResult + 1, 3) & " ";
For InxComb = 0 To UBound(Result(InxResult))
Debug.Print "[" & Result(InxResult)(InxComb) & "] ";
Next
Debug.Print
Next
End Sub
GenerateCombinations开展业务。
Sub GenerateCombinations(ByRef AllFields() As Variant, _
ByRef Result() As Variant)
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
' Discard unused trailing entries
ReDim Preserve ResultCrnt(0 To InxResultCrnt)
' Store this loop's combination in return array
Result(InxResult) = ResultCrnt
Next
End Sub
答案 1 :(得分:2)
这里有一些代码可以满足您的需求。它为每个元素分配一个零或一个,并连接分配了一个元素的元素。例如,使用四个元素,您有2 ^ 4个组合。代表为0和1,它看起来像
0000
0001
0010
0100
1000
0011
0101
1001
0110
1010
1100
0111
1011
1101
1110
1111
此代码创建一个数组(maInclude),它复制所有这16个场景,并使用相应的mvArr元素连接结果。
Option Explicit
Dim mvArr As Variant
Dim maResult() As String
Dim maInclude() As Long
Dim mlElementCount As Long
Dim mlResultCount As Long
Sub AllCombos()
Dim i As Long
'Initialize arrays and variables
Erase maInclude
Erase maResult
mlResultCount = 0
'Create array of possible substrings
mvArr = Array("NAME", "DESC", "DATE", "ACCOUNT")
'Initialize variables based on size of array
mlElementCount = UBound(mvArr)
ReDim maInclude(LBound(mvArr) To UBound(mvArr))
ReDim maResult(1 To 2 ^ (mlElementCount + 1))
'Call the recursive function for the first time
Eval 0
'Print the results to the immediate window
For i = LBound(maResult) To UBound(maResult)
Debug.Print i, maResult(i)
Next i
End Sub
Sub Eval(ByVal lPosition As Long)
Dim sConcat As String
Dim i As Long
If lPosition <= mlElementCount Then
'set the position to zero (don't include) and recurse
maInclude(lPosition) = 0
Eval lPosition + 1
'set the position to one (include) and recurse
maInclude(lPosition) = 1
Eval lPosition + 1
Else
'once lPosition exceeds the number of elements in the array
'concatenate all the substrings that have a corresponding 1
'in maInclude and store in results array
mlResultCount = mlResultCount + 1
For i = 0 To UBound(maInclude)
If maInclude(i) = 1 Then
sConcat = sConcat & mvArr(i) & Space(1)
End If
Next i
sConcat = Trim(sConcat)
maResult(mlResultCount) = sConcat
End If
End Sub
递归让我的头部受伤,但它肯定是强大的。此代码改编自Naishad Rajani,其原始代码可在http://www.dailydoseofexcel.com/archives/2005/10/27/which-numbers-sum-to-target/
找到答案 2 :(得分:0)
以Tony的答案为基础: (其中A = 4,B = 2,C = 1)
(以下是伪代码)
If (A And Inx <> 0) then
A = True
end if