juleskaynel
New Member
- Joined
- Mar 14, 2014
- Messages
- 11
I have a list of names and I want to randomly pair them in twos. How would I do this in Excel?
Example:
A1
A2
A3
A4
A5
A6
A7
A8
Example:
A1
A2
A3
A4
A5
A6
A7
A8
Option Explicit
Sub PickNamesAtRandom()
Dim HowMany As Integer
Dim NoOfNames As Long
Dim RandomNumber As Integer
Dim Names() As String 'Array to store randomly selected names
Dim i As Byte
Dim CellsOut As Long 'Variable to be used when entering names onto worksheet
Dim ArI As Byte 'Variable to increment through array indexes
Application.ScreenUpdating = False
HowMany = Range("D3").Value
CellsOut = 6
ReDim Names(1 To HowMany) 'Set the array size to how many names required
NoOfNames = Application.CountA(Range("A:A")) - 1 ' Find how many names in the list
i = 1
Do While i <= HowMany
RandomNo:
RandomNumber = Application.RandBetween(2, NoOfNames + 1)
'Check to see if the name has already been picked
For ArI = LBound(Names) To UBound(Names)
If Names(ArI) = Cells(RandomNumber, 1).Value Then
GoTo RandomNo
End If
Next ArI
Names(i) = Cells(RandomNumber, 1).Value ' Assign random name to the array
i = i + 1
Loop
'Loop through the array and enter names onto the worksheet
For ArI = LBound(Names) To UBound(Names)
Cells(CellsOut, 4) = Names(ArI)
CellsOut = CellsOut + 1
Next ArI
Application.ScreenUpdating = True
End Sub
Option Explicit
Sub randomPairs()
Dim v As Variant
Dim nv As Long, npair As Long
Dim i As Long, j As Long, x As Long
' Change "a1" to first cell of column of names
v = Range("a1", Range("a1").End(xlDown))
nv = UBound(v, 1)
npair = nv \ 2 ' truncate if nv is odd number (!)
ReDim pairs(1 To npair, 1 To 2) As Variant
Randomize
For i = 1 To npair: For j = 1 To 2
x = Int(nv * Rnd) + 1
pairs(i, j) = v(x, 1)
If x <> nv Then v(x, 1) = v(nv, 1)
nv = nv - 1
Next j, i
' change "b1" to first cell of pairs output
Range("b1").Resize(npair, 2) = pairs
End Sub
Some implementation notes:
Sub RandomPairing()
Dim Cnt As Long, RandomIndex As Long, Tmp As Variant, Arr As Variant
Randomize
Arr = Range("A1", Cells(Rows.Count, "A").End(xlUp))
For Cnt = UBound(Arr) To 1 Step -1
RandomIndex = Int((Cnt - LBound(Arr) + 1) * Rnd + LBound(Arr))
Tmp = Arr(RandomIndex, 1)
Arr(RandomIndex, 1) = Arr(Cnt, 1)
Arr(Cnt, 1) = Tmp
Next
Range("B1").Resize(UBound(Arr)) = Arr
Range("B1").Offset((1 + UBound(Arr)) / 2).Resize(UBound(Arr)).Cut Range("C1")
End Sub
Here is another macro for you to consider
My code works with 10 names for me. As a matter of fact, I just tried it with 1000 names and it worked nearly instantaneously for them as well.Odd: it works with 8 names, but not with 10 names.
Range("B1").Offset((1 + UBound(Arr)) / 2).Resize(UBound(Arr)).Cut Range("C1")
My code works with 10 names for me
Sub test()
[B:C].ClearContents
son = Cells(Rows.Count, 1).End(3).Row
lst = Application.Transpose(Range("A1:A" & son).Value)
For i = 1 To (son * 5)
s1 = WorksheetFunction.RandBetween(1, son)
s2 = WorksheetFunction.RandBetween(1, son)
If s1 <> s2 Then
tmp = lst(s2)
lst(s2) = lst(s1)
lst(s1) = tmp
End If
Next i
For i = 1 To son Step 2
say = say + 1
Cells(say, 2) = lst(i)
Cells(say, 3) = lst(i + 1)
Next i
End Sub
You are correct (as is the analysis you posted as well). My mistake was in forgetting that arrays formed by assigning a range to a Variant variable are always one-based (I set my code up as if they were zero-based). The correction is simple, though, all that is needed is to not add 1 to the UBound(Arr) in the code line you quoted in Message#8. Here is the corrected code...I don't know if or what code Rick tested, but his posted code certainly does not work for 10. By "does not work", I mean: it leaves two unpaired names in column B, as shown below.
Sub RandomPairing()
Dim Cnt As Long, RandomIndex As Long, Tmp As Variant, Arr As Variant
Randomize
Arr = Range("A1", Cells(Rows.Count, "A").End(xlUp))
For Cnt = UBound(Arr) To 1 Step -1
RandomIndex = Int((Cnt - LBound(Arr) + 1) * Rnd + LBound(Arr))
Tmp = Arr(RandomIndex, 1)
Arr(RandomIndex, 1) = Arr(Cnt, 1)
Arr(Cnt, 1) = Tmp
Next
Range("B1").Resize(UBound(Arr)) = Arr
Range("B1").Offset(UBound(Arr) / 2).Resize(UBound(Arr)).Cut Range("C1")
End Sub