![带有警告/标准的随机选择](https://linux22.com/image/1451135/%E5%B8%A6%E6%9C%89%E8%AD%A6%E5%91%8A%2F%E6%A0%87%E5%87%86%E7%9A%84%E9%9A%8F%E6%9C%BA%E9%80%89%E6%8B%A9.png)
我有一个 6 x 6 的网格。我将 36 个样本分成三组(A、B 和 C)。
我想要一个公式来随机排列网格中的样本。但是每行和每列必须包含每个组的两个样本。手动执行一两次很容易,但组合数量却非常多。
我对软件的选择持开放态度,只要它是免费软件或基于 Microsoft Office 的。
谢谢你!
答案1
我使用几个公式和一些 VBA 制作了一个用于生成随机行/列排列的工具。工作表布局如下所示:
参考网格是一个有效矩阵的简单示例,如 Gary 学生的初步答案中所述(可能已被删除)。行和列排列包含 6x6 网格的所有可能的唯一排列组合。 (如果需要,可以轻松修改以包括非唯一排列。)和中的值E12:E26
随机L12:L26
播种为零或一,以提供是否执行给定排列的基础。列D
和K
只是将它们转换为布尔值以简化 VBA 中的处理(见下文)。排列网格由自定义函数生成doSwap
,作为数组公式输入。按下F9
触发工作表重新计算会导致各种RAND
函数重新生成其随机值,从而更改要执行的排列系列。
实现此行为的 VBA 代码是:
Function doSwap(srcRg As Range, rowSwaps As Range, colSwaps As Range) As Variant
Dim workVt As Variant
Dim iter As Long
workVt = srcRg.Value
' Do row swaps
For iter = 1 To rowSwaps.Rows.Count
With rowSwaps
If .Cells(iter, 3).Value Then
workVt = swapRow(workVt, .Cells(iter, 1), .Cells(iter, 2))
End If
End With
Next iter
' Do col swaps
For iter = 1 To colSwaps.Rows.Count
With colSwaps
If .Cells(iter, 3).Value Then
workVt = swapCol(workVt, .Cells(iter, 1), .Cells(iter, 2))
End If
End With
Next iter
' Store and return
doSwap = workVt
End Function
Function swapCol(ByVal inArr As Variant, idx1 As Long, idx2 As Long) As Variant
Dim tempVal As Variant, workVt As Variant
Dim iter As Long
' Check if Range or Array input
If IsObject(inArr) Then
If TypeOf inArr Is Range Then
workVt = inArr.Value
Else
swapCol = "ERROR"
Exit Function
End If
Else
workVt = inArr
End If
' Just crash if not correct size
' Do swap
For iter = LBound(workVt, 1) To UBound(workVt, 1)
tempVal = workVt(iter, idx1)
workVt(iter, idx1) = workVt(iter, idx2)
workVt(iter, idx2) = tempVal
Next iter
' Return
swapCol = workVt
End Function
Function swapRow(ByVal inArr As Variant, idx1 As Long, idx2 As Long) As Variant
Dim tempVal As Variant, workVt As Variant
Dim iter As Long
' Check if Range or Array input
If IsObject(inArr) Then
If TypeOf inArr Is Range Then
workVt = inArr.Value
Else
swapRow = "ERROR"
Exit Function
End If
Else
workVt = inArr
End If
' Just crash if not correct size
' Do swap
For iter = LBound(workVt, 2) To UBound(workVt, 2)
tempVal = workVt(idx1, iter)
workVt(idx1, iter) = workVt(idx2, iter)
workVt(idx2, iter) = tempVal
Next iter
' Return
swapRow = workVt
End Function
上述代码的鲁棒性不是很好,但可以满足当前目的。如果需要,扩展/泛化应该非常简单。特别是,它应该可以按原样处理任何大小的 2-D 参考网格,即使是非正方形的网格。关键是确保正确设置排列指令数组。
编辑:玩了一会儿之后,很明显这个解决方案无法提供对可能排列的完整空间的访问。因此,我通过添加一个随机“移位“在它们之间交换类型标签。为了简化事情,我从ABC
标签切换到123
标签,这允许通过简单的MOD
操作实现,并且还可以以行和列总和的形式快速检查完整性:
答案2
有一个非常简单的方法可以实现这一点。首先预先分配插槽以下三种类型均适用:
然后取第一个样本,例如 SAMPLE_A_1,并将其放置在随机在其中一个 A 槽中。然后继续处理剩余的 35 个样本。
如果这种方法可以接受,我将发布一个简短的程序来填充矩阵。如果这种方法不可接受,我将删除此帖子。