【发布时间】:2019-01-13 15:09:41
【问题描述】:
大家好,我知道这个问题看起来与其他一些问题相似,但我已经广泛搜索它们,无法让它们为我工作。
我有 16 个数据集,我们称它们为 1 到 16。我想遍历所有可能的不同方法,将这 16 个数据集分为 4 个组;最基本的例子是:[1,2,3,4][5,6,7,8][9,10,11,12][13,14,15,16]。
问题是如何最好地遍历这些组合(在 vba 中)?
下面我提供了一个更详细的示例来帮助说明我正在努力实现的目标、我迄今为止的思考过程、我尝试过的代码以及它为什么不起作用。
示例另一个有效的组合可能是 [2,4,6,8][10,12,14,16][1,3,5,7][9,11,13, 15]等等。但是,我想避免任何重复:一种类型的重复将包括在一个组内重复的元素,或者相同组合的另一组:[1,2,2,4]... OR [1,2,3,4][4,5,6,7]... 2 类重复将涉及与前一次迭代相同的组,例如 [1,2,4, 3][5,6,8,7][9,10,12,11][13,14,16,15]。
思考过程我想避免任何重复,特别是因为这将大大减少我必须比较的组合数量。我试图通过使用比较组合中的所有元素以查看是否相同的函数来避免类型 1。我试图通过确保每个组中的元素始终按升序排列来避免类型 2,并确保每个组中的第一个元素也始终按升序排列。 (这应该有效,不是吗?)
代码 以下是我尝试过的两个代码示例。第一个简单地使 excel 崩溃(我确实有一个值,而不是 large number 如果这是你的想法);我想有太多的组合要一一经历? 第二个没有给我唯一的组,它返回相同的组,每个组中只有第一个值发生了变化。
1.
Sub CombGen()
Dim Combs(1 To 1820)
Dim Comb(1 To 4)
Dim GroupsCombs(1 To *large number*)
Dim GroupsComb(1 To 1820)
x = 1
For a = 1 To 16 - 3
Comb(1) = a
For b = a + 1 To 16 - 2
Comb(2) = b
For c = b + 1 To 16 - 1
Comb(3) = c
For d = c + 1 To 16
Comb(4) = d
Combs(x) = Comb
x = x + 1
Next d
Next c
Next b
Next a
x = 1
For a = 1 To 1820 - 3
GroupsComb(1) = a
For b = a + 1 To 1820 - 2
GroupsComb(2) = b
For c = b + 1 To 1820 - 1
GroupsComb(3) = c
For d = c + 1 To 1820
GroupsComb(4) = d
If Repeat(a, b, c, d, Combs) = False Then
GroupsCombs(x) = Comb
x = x + 1
End If
Next d
Next c
Next b
Next a
End Sub
Function Repeat(a, b, c, d, Combs)
Repeat = False
Dim letters(1 To 4): letters(1) = a: letters(2) = b: letters(3) = c: letters(4) = d
Dim i: Dim j
Repeat = False
For x = 1 To 4
For y = 2 To 4
For i = 1 To 4
For j = 1 To 4
If Combs(letters(i))(x) = Combs(letters(j))(y) Then
Repeat = True
End If
Next j
Next i
Next y
Next x
End Function
2.
For a = 1 To 16 - 3
For b = a + 1 To 16 - 2
For c = b + 1 To 16 - 1
For d = c + 1 To 16
TempGroups(1, 1) = a: TempGroups(1, 2) = b: TempGroups(1, 3) = c: TempGroups(1, 4) = d
For e = 1 To 16 - 3
If InArray(TempGroups, e) = False Then
For f = e + 1 To 16 - 2
If InArray(TempGroups, f) = False Then
For g = f + 1 To 16 - 1
If InArray(TempGroups, g) = False Then
For h = g + 1 To 16
If InArray(TempGroups, h) = False Then
TempGroups(2, 1) = e: TempGroups(2, 2) = f: TempGroups(2, 3) = g: TempGroups(2, 4) = h
For i = 1 To 16 - 3
If InArray(TempGroups, i) = False Then
For j = i + 1 To 16 - 2
If InArray(TempGroups, j) = False Then
For k = j + 1 To 16 - 1
If InArray(TempGroups, k) = False Then
For l = k + 1 To 16
If InArray(TempGroups, l) = False Then
TempGroups(3, 1) = i: TempGroups(3, 2) = j: TempGroups(3, 3) = k: TempGroups(3, 4) = l
For m = 1 To 16 - 3
If InArray(TempGroups, m) = False Then
For n = m + 1 To 16 - 2
If InArray(TempGroups, n) = False Then
For o = n + 1 To 16 - 1
If InArray(TempGroups, o) = False Then
For p = o + 1 To 16
If InArray(TempGroups, p) = False Then
TempGroups(3, 1) = m: TempGroups(3, 2) = n: TempGroups(3, 3) = o: TempGroups(3, 4) = p
If *comparison criteria are met* Then
For x = 1 To 4
For y = 1 To 4
Groups(x, y) = TempGroups(x, y)
Next y
Next x
End If
End If
Next p
End If
Next o
End If
Next n
End If
Next m
End If
Next l
End If
Next k
End If
Next j
End If
Next i
End If
Next h
End If
Next g
End If
Next f
End If
Next e
Next d
Next c
Next b
Next a
End If
Groups 和 TempGroups 是二维数组,第一个值是组编号,第二个值是该组中的元素编号。
InArray 是我制作的一个函数(相当不言自明)
在这种情况下,我使用比较标准将最近的“最佳”组集与“临时组”的当前迭代进行比较,并保存最佳组,以便与下一次迭代进行比较
没有帮助的链接:
How can I iterate throught every possible combination of n playing cards
虽然这很有用,但它只查看了集合中一个组的组合,我想查看集合中多个组的组合
Listing all permutations of a given set of values 这更多地着眼于排列(重新排列组的顺序而不是组合)
我查看的几乎所有其他解决方案都属于这些类别之一
【问题讨论】:
-
如果您链接到其他解决方案并说明它们为什么不适合您,您的问题将会得到改善。
-
this answer 不提供见解或指导吗?任何方式你做到这一点,排列的数量将是非常大的。
-
@PeterT 感谢您的回复。不幸的是,您链接的答案集中在排列和 Steinhaus 算法上;这只会交换我组中列出的每个元素的顺序,即从 [1234] 到 [1243] - 正如我所描述的那样,这是一种类型 2 重复。我不想要对我的组进行排序的每一个排列,我只想要每一个独特的组合来比较它们。
-
@JamesJenkins 我在底部添加了几个链接,包括彼得建议的链接,以及我遇到的问题
-
我想我理解类型 1(不太确定),我对你对类型 2 组合的定义肯定有点困惑。你能给出这两种类型的更广泛的例子吗?我想我有一个优雅的解决方案来解决您的问题。
标签: excel vba iteration combinations permutation