如果我没看错,你基本上只是想对数组进行洗牌,同时还施加一个约束,即没有 user ID 不能最终对应于自身。
您可以通过多种方式实现这一点。下面的方法不是很通用,可以重构(使用更多的函数/子例程)并且有点笨拙。尽管如此,它可能没问题,并且可能会给您一些关于实施的想法:
Option Explicit
Private Function GetArrayOfNames(ByVal someRange As Range) As Variant
' someRange should be a single-column, vertical range.
Debug.Assert someRange.Columns.Count = 1
Debug.Assert someRange.Areas.Count = 1
Debug.Assert someRange.Rows.Count > 1
GetArrayOfNames = someRange.Value
End Function
Private Sub SecretSantaShuffle()
' This procedure will overwrite the contents of the initial range,
' and the three columns to its right.
Dim rangeContainingNames As Range
Set rangeContainingNames = ThisWorkbook.Worksheets("Sheet1").Range("A2:A7")
Dim inputArray() As Variant
inputArray = GetArrayOfNames(rangeContainingNames)
Dim rowCount As Long
rowCount = UBound(inputArray, 1)
ReDim Preserve inputArray(1 To rowCount, 1 To 4)
Const NAME_COLUMN_INDEX As Long = 1
Const UID_COLUMN_INDEX As Long = 2
Const RANDOM_NAME_COLUMN_INDEX As Long = 3
Const RANDOM_UID_COLUMN_INDEX As Long = 4
Do
Dim userIdPool As Collection
Set userIdPool = New Collection
Dim rowIndex As Long
For rowIndex = LBound(inputArray, 1) To UBound(inputArray, 1)
inputArray(rowIndex, UID_COLUMN_INDEX) = rowIndex
userIdPool.Add rowIndex, Key:=CStr(rowIndex)
Next rowIndex
For rowIndex = LBound(inputArray, 1) To UBound(inputArray, 1)
Dim randomRowIndex As Long
Do While True
randomRowIndex = userIdPool.Item(Application.RandBetween(1, userIdPool.Count))
If randomRowIndex <> rowIndex Then Exit Do
If userIdPool.Count = 1 Then Exit Do
DoEvents
Loop
userIdPool.Remove CStr(randomRowIndex)
inputArray(rowIndex, RANDOM_NAME_COLUMN_INDEX) = inputArray(randomRowIndex, NAME_COLUMN_INDEX)
inputArray(rowIndex, RANDOM_UID_COLUMN_INDEX) = inputArray(randomRowIndex, UID_COLUMN_INDEX)
Next rowIndex
Loop While userIdPool.Count > 0
rangeContainingNames.Resize(UBound(inputArray, 1), UBound(inputArray, 2)).Value = inputArray
End Sub
您可能需要更改分配给rangeContainingNames 的内容。我的姓名列表在工作表 Sheet1 的范围 A2:A7 中,但您应该更改工作表名称和范围地址以反映您姓名的位置。