xlsm file error upon sending through email - excel

I am a newbie vba coder here.
I have created an .xlsm with userform. Everything works fine in my computer, but when I send the file over via email, the recipient will encounter the following issues when opening the file:
I added an event handler on Workbook_Open to automatically open the userform. When the recipient open the file, it will receive this error and Debug button returns to this line:
When Submit button of the Userform is clicked, the data is supposed to be transferred to 'ThisWorkbook' but instead it creates a new file (i guess the previous version) and paste the data there.
Can anyone help me to figure out what went wrong with my file? Thank you.
Below is my code:
Inside Workbook Event Handler:
Sub Workbook_Open()
RunForm
End Sub
Module1:
Option Explicit
Option Base 1
Sub PopulateComboBox()
Dim PaymentTerms() As String, PaymentFreq() As String, PaymentTermsAlt() As String
Dim i As Integer, j As Integer, m As Integer, n As Integer, o As Integer
j = WorksheetFunction.CountA(Sheets("Populate").Columns("A:A"))
n = WorksheetFunction.CountA(Sheets("Populate").Columns("B:B"))
ReDim PaymentTerms(j - 1) As String
ReDim PaymentFreq(n - 1) As String
ReDim PaymentTermsAlt(j - 1) As String
For i = 1 To j - 1
PaymentTerms(i) = ThisWorkbook.Sheets("Populate").Range("A2:A" & (j - 1)).Cells(i, 1)
UserForm1.ComboTerms.AddItem PaymentTerms(i)
Next i
For m = 1 To n - 1
PaymentFreq(m) = ThisWorkbook.Sheets("Populate").Range("B2:B" & (n - 1)).Cells(m, 1)
UserForm1.ComboFreq.AddItem PaymentFreq(m)
Next m
For o = 1 To j - 1
PaymentTermsAlt(o) = ThisWorkbook.Sheets("Populate").Range("A2:A" & (j - 1)).Cells(o, 1)
UserForm1.ComboTermsAlt.AddItem PaymentTermsAlt(o)
Next o
UserForm1.ComboTerms.Text = PaymentTerms(1)
UserForm1.ComboFreq.Text = PaymentFreq(1)
UserForm1.ComboTermsAlt.Text = PaymentTermsAlt(1)
End Sub
Sub RunForm()
ThisWorkbook.Sheets("Printout").Activate
UserForm1.Show
End Sub
Inside Userform:
Option Explicit
Sub CommandButton1_Click()
Application.ScreenUpdating = False
If Not IsNumeric(BasePay) Or Not IsNumeric(Interest) Then
MsgBox ("Please Enter Numeric Value for Base Pay or Interest Rate")
Exit Sub
End If
If BasePay < 0 Or Interest < 0 Then
MsgBox ("Base Pay or Interest cannot be negative value")
Exit Sub
End If
ThisWorkbook.Sheets("Printout").Range("A1") = "Prepared For " & ClientName
ThisWorkbook.Sheets("Printout").Range("O1").Value = BasePay.Text
ThisWorkbook.Sheets("Printout").Range("S2").Value = Interest.Text / 100
ThisWorkbook.Sheets("Printout").Range("L3").Value = ComboTerms.Text
ThisWorkbook.Sheets("Printout").Range("O3").Value = ComboFreq.Text
ThisWorkbook.Sheets("Printout").Range("Q2").Value = ComboTermsAlt.Text
If NewCar Then
ThisWorkbook.Sheets("Printout").Range("U2").Value = "New"
Else
ThisWorkbook.Sheets("Printout").Range("U2").Value = "Used"
End If
'----- Transfer Add-On Items to Printout Sheet ---------
Dim i As Integer
Dim j As Integer
Dim k As Integer
k = 6
For i = 1 To 9
ThisWorkbook.Sheets("Printout").Cells(k, 1).MergeArea.ClearContents
k = k + 2
Next
k = 6
For i = 10 To 18
ThisWorkbook.Sheets("Printout").Cells(k, 5).MergeArea.ClearContents
k = k + 2
Next
k = 6
For i = 19 To 27
ThisWorkbook.Sheets("Printout").Cells(k, 9).MergeArea.ClearContents
k = k + 2
Next
k = 6
For i = 28 To 36
ThisWorkbook.Sheets("Printout").Cells(k, 13).MergeArea.ClearContents
k = k + 2
Next
'---- Category 1 ------
i = 6
For j = 1 To 9
If UserForm1.Controls("Checkbox" & j).Value = True Then
ThisWorkbook.Sheets("Printout").Range("A" & i).Value = Me.Controls("Checkbox" & j).Caption
i = i + 2
Else
ThisWorkbook.Sheets("Printout").Range("A" & i).Value = ""
End If
Next j
'---- Category 2 ------
i = 6
For j = 10 To 18
If UserForm1.Controls("Checkbox" & j).Value = True Then
ThisWorkbook.Sheets("Printout").Range("E" & i).Value = Me.Controls("Checkbox" & j).Caption
i = i + 2
Else
ThisWorkbook.Sheets("Printout").Range("E" & i).Value = ""
End If
Next j
'---- Category 3 ------
i = 6
For j = 19 To 27
If UserForm1.Controls("Checkbox" & j).Value = True Then
ThisWorkbook.Sheets("Printout").Range("I" & i).Value = Me.Controls("Checkbox" & j).Caption
i = i + 2
Else
ThisWorkbook.Sheets("Printout").Range("I" & i).Value = ""
End If
Next j
'---- Category 4 ------
i = 6
For j = 28 To 36
If UserForm1.Controls("Checkbox" & j).Value = True Then
ThisWorkbook.Sheets("Printout").Range("M" & i).Value = Me.Controls("Checkbox" & j).Caption
i = i + 2
Else
ThisWorkbook.Sheets("Printout").Range("M" & i).Value = ""
End If
Next j
UserForm1.Hide
End Sub
Sub CommandButton2_Click()
Unload UserForm1
UserForm1.Show
End Sub
Sub CommandButton3_Click()
Unload UserForm1
End Sub
Sub NewCar_Click()
Dim LastRow As Integer
Dim i As Integer
Dim j As Integer
LastRow = WorksheetFunction.CountA(Sheets("Populate").Columns("D:D"))
'---- Count No of Checkbox
Dim Ctrl As MSForms.Control
Dim n As Integer
Dim cbcount As Long
For n = 0 To Me.Controls.Count - 1
If Left(UserForm1.Controls(n).Name, 8) = "CheckBox" Then
cbcount = cbcount + 1
End If
Next n
i = 2 '--- Preset counter i
For j = 1 To cbcount
UserForm1.Controls("Checkbox" & j).Caption = ThisWorkbook.Sheets("Populate").Cells(i, 4).Value
i = i + 1
If i > LastRow And i < (cbcount / 4) Then
UserForm1.Controls("Checkbox" & j).Caption = ""
End If
If i > LastRow And i > (cbcount / 4 + 1) Then
i = 2
End If
Next j
End Sub
Sub UsedCar_Click()
Dim LastRow As Integer
Dim i As Integer
Dim j As Integer
LastRow = WorksheetFunction.CountA(Sheets("Populate").Columns("D:D"))
'---- Count No of Checkbox
Dim Ctrl As MSForms.Control
Dim n As Integer
Dim cbcount As Long
For n = 0 To Me.Controls.Count - 1
If Left(Me.Controls(n).Name, 8) = "CheckBox" Then
cbcount = cbcount + 1
End If
Next n
i = 2 '--- Preset counter i
For j = 1 To cbcount
UserForm1.Controls("Checkbox" & j).Caption = ThisWorkbook.Sheets("Populate").Cells(i, 8).Value
i = i + 1
If i > LastRow And i < (cbcount / 4) Then
UserForm1.Controls("Checkbox" & j).Caption = ""
End If
If i > LastRow And i > (cbcount / 4 + 1) Then
i = 2
End If
Next j
End Sub
Sub UserForm_Initialize()
Call PopulateComboBox
'----- Rename Frame Boxes Caption
Dim k As Integer, nc As Integer
nc = 1
For k = 2 To 5
Me.Controls("Frame" & k).Caption = ThisWorkbook.Sheets("Printout").Cells(5, nc)
nc = nc + 4
Next k
'--------------------------------------------------
Dim LastRow As Integer
Dim i As Integer
Dim j As Integer
LastRow = WorksheetFunction.CountA(ThisWorkbook.Sheets("Populate").Columns("D:D"))
'---- Count No of Checkbox
Dim Ctrl As MSForms.Control
Dim n As Integer
Dim cbcount As Long
For n = 0 To Me.Controls.Count - 1
If Left(Me.Controls(n).Name, 8) = "CheckBox" Then
cbcount = cbcount + 1
End If
Next n
i = 2 '--- Preset counter i
For j = 1 To cbcount
UserForm1.Controls("Checkbox" & j).Caption = ThisWorkbook.Sheets("Populate").Cells(i, 4).Value
i = i + 1
If i > LastRow And i < (cbcount / 4) Then
UserForm1.Controls("Checkbox" & j).Caption = ""
End If
If i > LastRow And i > (cbcount / 4 + 1) Then
i = 2
End If
Next j
End Sub

Related

VBA - Run-time error 1004 (application-defined or objecy-defined error)

The code is not working in this way, but if i use ('Wks_So.Range("A9:A150").ClearContents), instead of (Wks_So.Range("A9", Range("A9").End(xlDown)).ClearContents), the code has no problem at all.
My aim for the selection is to clear all the contents from A9 to the last cell of column A with values
Dim i As Integer
Dim j As Integer
Dim x As Integer
Application.Calculation = xlCalculationManual
Set Wks_Sb = Worksheets("Scarico_Bond")
Set Wks_So = Worksheets("Scarico_Other")
Set Wks_I = Worksheets("Invio")
Wks_Sb.Range("A9", Range("A9").End(xlDown)).ClearContents
'Wks_Sb.Range("A9:A150").ClearContents
Wks_So.Range("A9", Range("A9").End(xlDown)).ClearContents
here is the error
'Wks_So.Range("A9:A50").ClearContents
Wks_Sb.Range("D9:D140").Interior.Color = vbWhite
j = 9
k = 9
x = 8
For i = 7 To 150
If InStr(1, (Wks_I.Cells(i, 4).Value), "Obbligazioni") > 0 Then
Wks_Sb.Cells(j, 1) = x - 7
j = j + 1
Else
If InStr(1, (Wks_I.Cells(i, 4).Value), "Fondi/ETF") > 0 Then
Wks_So.Cells(k, 1) = x - 7
k = k + 1
End If
End If
x = x + 1
Next i
Application.Calculation = xlCalculationAutomatic
End Sub
I would do like this and also define some variables:
Sub yourSub()
Dim i, j, k, x As Integer
Dim lastRow_Sb, lastRow_So, lastRow_I as Integer
Dim wb As Workbook
Dim Wks_Sb, Wks_So, Wks_I As Worksheet
Set wb = ActiveWorkbook
Set Wks_Sb = wb.Worksheets("Scarico_Bond")
Set Wks_So = wb.Worksheets("Scarico_Other")
Set Wks_I = wb.Worksheets("Invio")
lastRow_Sb = Wks_Sb.Cells.SpecialCells(xlLastCell).Row
lastRow_So = Wks_So.Cells.SpecialCells(xlLastCell).Row
lastRow_I = Wks_I.Cells.SpecialCells(xlLastCell).Row
Application.ScreenUpdating = False
Wks_Sb.Range("A9:A" & lastRow_Sb).ClearContents
Wks_So.Range("A9:A" & lastRow_So).ClearContents
Wks_Sb.Range("D9:D140").Interior.Color = vbWhite
j = 9
k = 9
x = 8
For i = 7 To lastRow_I 'Or should this always be 150?
If InStr(1, (Wks_I.Cells(i, 4).Value), "Obbligazioni") > 0 Then
Wks_Sb.Cells(j, 1) = x - 7
j = j + 1
Else
If InStr(1, (Wks_I.Cells(i, 4).Value), "Fondi/ETF") > 0 Then
Wks_So.Cells(k, 1) = x - 7
k = k + 1
End If
End If
x = x + 1
Next i
Application.ScreenUpdating = True
End Sub
You should use End(xlUp) instead of twice End(xlDown):
Change
Wks_Sb.Range("A9", Range("A9").End(xlDown)).ClearContents
'Wks_Sb.Range("A9:A150").ClearContents
Wks_So.Range("A9", Range("A9").End(xlDown)).ClearContents
to:
Wks_Sb.Range("A9", Wks_Sb.Range("A1000000").End(xlUp)).ClearContents

Problem with finding similar numbers in 2 columns in vba

i have problem with my code in vba. I have to find how much similar numbers are in column 1 and 2, but for example Column 1 (6,6,34,21,23,40) and column2 (49,34,6,9,6,20) should write 3 cause there are pairs 6-6, 6-6 and 34-34. I know its messy explenation but i hope its understandable. My code so far is:
Sub totolotek()
Dim i As Integer
Dim x As Integer
Dim j As Integer
Dim liczba As Integer
Dim suma As Integer
Dim ileLosowan As Integer
Range("B2:C7").Interior.Color = RGB(135, 134, 125)
Range("B2:B7").Font.ColorIndex = 3
Range("C2:C7").Font.ColorIndex = 5
ileLosowan = 7
Randomize
For i = 2 To ileLosowan
x = Int(Rnd * (49) + 1)
Range("c" & i) = x
Next i
For i = 2 To 7
liczba = Range("c" & i)
For j = 2 To 7
liczbe = Range("b" & j)
If liczbe = liczba Then
Range("c" & i).Interior.Color = RGB(255, 255, 0)
Range("b" & j).Interior.Color = RGB(255, 255, 0)
suma = suma + 1
End If
Next j
Next i
Range("c" & 9) = suma
End Sub
Try this. I invested some time and I added some lines of code. The macro find all the number pairs.
Example (6,6,3,4,2) (2,3,6,9,0) --> results 3: (6-6, 3-3, 2-2)
Sub totolotek()
Dim i As Integer
Dim x As Integer
Dim j As Integer
Dim liczba As Integer
Dim suma As Integer
Dim ileLosowan As Integer
Dim str_B As String, str_C As String, str_BC As String
Dim max_rand As Long
ileLosowan = 20 ' you can change the number of element in the column
max_rand = 49 ' max randum number
start_row = 2 'start_row
str_BC = "B2:C" & ileLosowan
str_B = "B2:B" & ileLosowan
str_C = "C2:C" & ileLosowan
Range(str_BC).Interior.Color = RGB(135, 134, 125)
Range(str_B).Font.ColorIndex = 5
Range(str_C).Font.ColorIndex = 5
Randomize
For i = start_row To ileLosowan
x = Int(Rnd * (max_rand) + 1)
Range("C" & i) = x
Next i
For i = start_row To ileLosowan
x = Int(Rnd * (max_rand) + 1)
Range("B" & i) = x
Next i
liczba_array = Range("B" & start_row & ":B" & ileLosowan).Value2
liczbe_array = Range("C" & start_row & ":C" & ileLosowan).Value2
ReDim ID_array(1 To 1)
ID_array(1) = max_rand + 1
Count = 1
For i = 1 To UBound(liczba_array, 1)
For j = 1 To UBound(liczbe_array, 1)
For k = 1 To UBound(ID_array, 1)
If ID_array(k) = j Then
GoTo out
End If
Next k
If liczba_array(i, 1) = liczbe_array(j, 1) Then
Range("B" & (start_row + i - 1)).Interior.Color = RGB(150 + Count * 20, 0, 0)
Range("C" & (start_row + j - 1)).Interior.Color = RGB(150 + Count * 20, 0, 0)
suma = suma + 1
ID_array(Count) = j
Count = Count + 1
ReDim Preserve ID_array(1 To Count)
Exit For
End If
Next j
out:
Next i
Range("C" & ileLosowan + 2) = suma
End Sub
Something like this will do what you're after. Just incorporate it into you're code cause I don't really know what's going on there.
Dim i As Long, j As Long, arr As Variant, Total As Integer
For i = 2 To 7 'Rows to loop through in the column
Total = 0
arr = Split(Range("A" & i), ",") 'Split column A using the comma
For j = 0 To UBound(arr) 'Loop through the split values
If InStr(Range("B" & i), arr(j)) > 0 Then 'Find if value is within other column
Total = Total + 1 'If it is, add 1 to total
End If
Next j
Range("C" & i) = Total 'Write total to another column on same row
Next i
Or if you want a basic function for it that you can use in your sheet you can use this:
Public Function CountMatches(Cell As String, Rng As Range, Optional Delim As String)
Dim i As Long, j As Long, arr As Variant, Total As Integer
If Delim = "" Then Delim = ","
If Rng.Count > 1 Then
CountMatches = "Please choose 1 cell to compare to."
Exit Function
End If
Total = 0
arr = Split(Cell, Delim) 'Split column A using the comma
For j = 0 To UBound(arr) 'Loop through the split values
If InStr(Rng, arr(j)) > 0 Then 'Find if value is within other column
Total = Total + 1 'If it is, add 1 to total
End If
Next j
CountMatches = Total
End Function
Use it like =CountMatches(A1,B1,",")

Excel VBA: how to apply bold format to all words before ":"?

I am trying to apply the bold format to all words before a colon (:) in a specific cell. In the image, the words first / second / third need to be in bold, the rest not.
I found the following code on a different thread, but it applies the bold format to the first word before a colon.
Sub PreColon()
Dim i As Long, N As Long, s As String, j As Long
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To N
s = Cells(i, 1)
j = InStr(1, s, ":")
If j <> 0 Then
Cells(i, 1).Characters(1, j - 1).Font.Bold = True
End If
Next i
End Sub
split on the - and do a second loop:
Sub PreColon()
With ActiveSheet
Dim N As Long
N = .Cells(.Rows.Count, "A").End(xlUp).Row
Dim i As Long
For i = 1 To N
Dim strLen As Long
strLen = 0
Dim sArray() As String
sArray = Split(.Cells(i, 1), "-")
Dim s As Variant
For Each s In sArray
Dim j As Long
j = InStr(s, ":")
If j > 0 Then
.Cells(i, 1).Characters(strLen + 1, j - 1).Font.Bold = True
End If
strLen = strLen + Len(s) + 1
Next s
Next i
End With
End Sub
Here is a little procedure you can use:
Sub Test()
Dim i As Long, N As Long
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To N
FormatPreColon Cells(i, 1)
Next
End Sub
Sub FormatPreColon(Rng As Range)
Dim i As Long, j As Long
If TypeName(Rng.Value) <> "String" Then Exit Sub
i = InStr(1, Rng, ":")
Do While i <> 0
j = InStrRev(Rng, " ", i) + 1
Rng.Characters(j, i - j).Font.Bold = True
i = InStr(i + 1, Rng, ":")
Loop
End Sub
Possible missing "-" symbol you may use this.
Dim i As Long, s As String, j As Integer, k As Integer, t As String, counter As Integer, N As Integer
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To N
s = Cells(i, 1)
j = 1
k = 1
Do While j > 0
j = InStr(k, s, ":")
k = j + 1
counter = 1
For m = j - 1 To 1 Step -1
t = Trim(Mid(s, m, 1))
If (t = "" Or m = 1) Then
Cells(i, 1).Characters(m, counter).Font.Bold = True
Exit For
Else
counter = counter + 1
End If
Next m
Loop
DoEvents
Next i
MsgBox "Finito..."

Any suggestions on speeding this code up?

Ok, I have the code below, which takes 18 different words, all in Column A rows 1 to 18, and tries them in all different combos to find a seven word palindrome. I am pretty sure the code will get it done, but it just searches for a LONG time. I know there's a way to check the first and last letters of the combos, to make sure they're the same, before the code runs them through the REVERSE function, I just can't figure out how to do it. I am very new to this.In other words, each time it puts together 7 of the words, if it didn't have to go through the REVERSE function, a ton of time would be saved, and verification that the first and last letters match would do that. Thanks in advance for any help
Sub SevenDrome()
Dim count As Integer
count = 0
Dim wordtest As String
Dim wordpal As String
For j = 1 To 18
For k = 1 To 18
For l = 1 To 18
For m = 1 To 18
For n = 1 To 18
For o = 1 To 18
For p = 1 To 18
wordtest = Cells(j, 1) & Cells(k, 1) & Cells(l, 1) & Cells(m, 1) & Cells(n, 1) & Cells(o, 1) & Cells(p, 1)
wordpal = REVERSE(wordtest)
If wordtest = wordpal Then
count = count + 1
Cells(count, 7) = wordtest
End If
Next p
Next o
Next n
Next m
Next l
Next k
Next j
End Sub
Try, This results in 104,976 which takes less than 2 seconds.
Sub test()
Dim a(1 To 18)
Dim vR(1 To 1000000, 1 To 1)
Dim cnt As Long
Dim i As Integer, k As Integer, l As Integer
Dim m As Integer, n As Integer, o As Integer
For i = 1 To 18
a(i) = Range("a" & i)
Next i
For j = 1 To 18
For k = 1 To 18
If a(j) = a(k) Then
For l = 1 To 18
For m = 1 To 18
If a(l) = a(m) Then
For n = 1 To 18
For o = 1 To 18
If a(n) = a(o) Then
For p = 1 To 18
cnt = cnt + 1
vR(cnt, 1) = a(j) & a(l) & a(n) & a(p) & a(o) & a(m) & a(k)
DoEvents
Next p
End If
Next o
Next n
End If
Next m
Next l
End If
Next k
Next j
Range("g1").Resize(cnt) = vR
End Sub
Data image
Result Image
If each cell has more than 2 characters, you can do as follows.
Sub test2()
Dim a(1 To 18)
Dim vR(1 To 1000000, 1 To 1)
Dim cnt As Long
Dim i As Integer, k As Integer, l As Integer
Dim m As Integer, n As Integer, o As Integer
For i = 1 To 18
a(i) = Range("a" & i)
Next i
For j = 1 To 18
For k = 1 To 18
If a(j) = Reverse(a(k)) Then
For l = 1 To 18
For m = 1 To 18
If a(l) = Reverse(a(m)) Then
For n = 1 To 18
For o = 1 To 18
If a(n) = Reverse(a(o)) Then
For p = 1 To 18
If a(p) = Reverse(a(p)) Then
cnt = cnt + 1
vR(cnt, 1) = a(j) & a(l) & a(n) & a(p) & a(o) & a(m) & a(k)
DoEvents
End If
Next p
End If
Next o
Next n
End If
Next m
Next l
End If
Next k
Next j
Range("g1").CurrentRegion.Clear
If cnt Then
Range("g1").Resize(cnt) = vR
End If
End Sub
Function Reverse(s)
Dim i As Integer
Dim myS As String
For i = Len(s) To 1 Step -1
myS = myS & Mid(s, i, 1)
Next i
Reverse = myS
End Function
Case 2 Data
Case 2 Result

Shuffling a 2D array

I have the follow script to put a list of people with there know skills in an array and then match the first match with a customer with the same skill. Every time it runs the results are the same. I would like to have it be a random order of the array, but keeping the two columns in the array together. How can I shuffle(rearrange) the array that keeps the rows in the array the same? Or would it be better to erase the array, randomly sort the columns and set the array back up?
Sub Assign()
Dim arOne()
ReDim arOne(1000, 15)
Dim o As Integer
Dim p As Integer
Dim StartTime As Double
Dim MinutesElapsed As String
p = 0
o = 0
For i = 2 To 920
If Cells(i, 12).Value <> Cells(i - 1, 12) Then
p = p + 1
arOne(p, 0) = Cells(i, 12).Value
arOne(p, 1) = Cells(i, 13).Value
o = 2
Else
arOne(p, o) = Cells(i, 13).Value
o = o + 1
End If
Next
For i = 2 To 612
For o = LBound(arOne, 1) + 1 To UBound(arOne, 1)
If arOne(o, 0) <> "" Then
iUsed = Application.WorksheetFunction.CountIf(Range("C2:C" & i), "=" & arOne(o, 0))
If iUsed < Application.WorksheetFunction.VLookup(arOne(o, 0), Range("Q2:R62"), 2, False) Then
For j = LBound(arOne, 2) + 1 To UBound(arOne, 2)
If arOne(o, j) = Cells(i, 2).Value Then
Cells(i, 3).Value = arOne(o, 0)
ActiveSheet.Calculate
GoTo NextIR
End If
Next j
End If
End If
Next o
NextIR:
Next i
End Sub
Multiple loops and multiple access to range objects makes your code very, very slow (I don't know if performance is important).
I would read all necessary data to arrays and use filter and rnd to get a random person with the relevant skill:
Option Explicit
Sub PeopleBusiness()
Dim People, Customers, FilterArray
Dim I As Long, Idx As Long
People = Application.Transpose([L2:L920 & "|" & M2:M8])
Customers = Range("A2:C612").Value2
For I = 1 To UBound(Customers, 1)
FilterArray = Filter(People, Customers(I, 2))
If UBound(FilterArray) > -1 Then
Idx = Round(Rnd() * UBound(FilterArray), 0)
Customers(I, 3) = Left(FilterArray(Idx), InStr(1, FilterArray(Idx), "|") - 1)
End If
Next I
Range("A2:C612").Value = Customers
End Sub
I was able to get done what I needed by erasing the array and redimming it after sorting the data based on a rand() number in the table. It takes about 15 minutes to run 7000 assignment but it is a lot better than 7+ hours it takes to do manually.
Sub Assign()
Dim arOne()
ReDim arOne(1000, 15)
Dim o As Integer
Dim p As Integer
Dim StartTime As Double
Dim MinutesElapsed As String
Application.Calculation = xlAutomatic
StartTime = Timer
NextIR:
ReDim arOne(1000, 15)
p = 0
o = 0
QAlr = Sheets("Sheet1").Range("L" & Rows.Count).End(xlUp).Row
For I = 2 To QAlr
If Cells(I, 12).Value <> Cells(I - 1, 12) Then
p = p + 1
arOne(p, 0) = Cells(I, 12).Value
arOne(p, 1) = Cells(I, 13).Value
o = 2
Else
arOne(p, o) = Cells(I, 13).Value
o = o + 1
End If
Next
AQAlr = Sheets("Sheet1").Range("C" & Rows.Count).End(xlUp).Row
AgtLr = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
For I = AQAlr + 1 To AgtLr
For o = LBound(arOne, 1) + 1 To UBound(arOne, 1)
If arOne(o, 0) <> "" Then
iUsed = Application.WorksheetFunction.CountIf(Range("C2:C" & I), "=" & arOne(o, 0))
If iUsed < Application.WorksheetFunction.VLookup(arOne(o, 0), Range("Q2:R62"), 2, False) Then
For j = LBound(arOne, 2) + 1 To UBound(arOne, 2)
If arOne(o, j) = Cells(I, 2).Value Then
Cells(I, 3).Value = arOne(o, 0)
ActiveSheet.Calculate
Erase arOne()
ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort.SortFields.Add _
Key:=Range("Table1[[#All],[Random '#]]"), SortOn:=xlSortOnValues, Order:= _
xlDescending, DataOption:=xlSortTextAsNumbers
With ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
GoTo NextIR
End If
Next j
End If
End If
Next o
Next I
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
MsgBox "Assignments completed in " & MinutesElapsed & " minutes", vbInformation
End Sub
Not entirely sure I got your set-up right but you can try this:
Option Explicit
Sub Assign()
Randomize
Range("C2", Range("C" & Rows.Count).End(xlUp)).ClearContents
Dim R1 As Range: Set R1 = Range("L2:M920") 'People skill table
Dim R2 As Range: Set R2 = Range("A2:B612") 'Cusotmers skill talbe
Dim D0 As Object: Set D0 = CreateObject("scripting.dictionary")
Dim i As Integer, j As Integer, Rand as Integer
For i = 1 To R2.Rows.Count
Rand = Int(R1.Rows.Count * Rnd + 1)
For j = 1 To R1.Rows.Count
If R1.Cells(Rand, 2) = R2(i, 2) And Not D0.exists(Rand) Then
R2.Cells(i, 2).Offset(0, 1) = R1(Rand, 1)
D0.Add Rand, Rand
Exit For
End If
Rand = (Rand Mod R1.Rows.Count) + 1
Next j
Next i
End Sub
The idea is to check the people skill list starting from a random point and making sure a key is not used twice.
EDIT:
According to your comment I assume a "people / skill" can then be assigned more than once as there are 7000+ customers ?
Code below randomly assign with a fairly good distribution 1500 peoples to 7000 customers in +/- 1 second.
Have a try and see if you can adapt it to your project.
Option Explicit
Sub Assign()
Application.ScreenUpdating = False
Dim Start: Start = Timer
Randomize
Range("C2:C99999").ClearContents
Dim D1 As Object
Dim R1 As Range: Set R1 = Range("L2", Range("M" & Rows.Count).End(xlUp))
Dim R2 As Range: Set R2 = Range("A2", Range("B" & Rows.Count).End(xlUp))
Dim T1: T1 = R1
Dim T2: T2 = R2
Dim T3()
Dim a As Integer: a = 1
Dim i As Integer, j As Integer, k As Integer, Rnd_Val As Integer, j_loop As Integer
For i = 1 To (Int(R2.Rows.Count / R1.Rows.Count) + 1)
Set D1 = CreateObject("scripting.dictionary")
For j = (R1.Rows.Count * i - R1.Rows.Count + 1) To R1.Rows.Count * i
ReDim Preserve T3(1 To j)
Rnd_Val = Int(Rnd * R1.Rows.Count + 1)
For k = 1 To R1.Rows.Count
If T1(Rnd_Val, 2) = T2(j, 2) And Not D1.exists(Rnd_Val) And T3(j) = "" Then
T3(j) = T1(Rnd_Val, 1)
D1.Add Rnd_Val, Rnd_Val
Exit For
End If
Rnd_Val = (Rnd_Val Mod R1.Rows.Count) + 1
Next k
If T3(j) = "" Then
For k = 1 To R1.Rows.Count
If T1(Rnd_Val, 2) = T2(j, 2) Then
T3(j) = T1(Rnd_Val, 1)
Exit For
End If
Rnd_Val = (Rnd_Val Mod R1.Rows.Count) + 1
Next k
End If
a = a + 1
If a > R2.Rows.Count Then GoTo EndLoop
Next j
Set D1 = Nothing
Next i
EndLoop:
Range("C2").Resize(UBound(T3), 1) = Application.Transpose(T3)
Debug.Print Timer - Start
Application.ScreenUpdating = True
End Sub

Resources