Compare Employee Names To Master List - vba

I am comparing a list of employees to a master list, and getting a count. This works as it should, but now I need to add a caveat to ignore certain employee names (like Manager, Supervisor, Mgr, Sup) from the counts.
The list received has location in column A and the names in column C - so I would need to ignore the names in the array above that would exist in Column C from the counts.
...
This is what I am using to return the count -> how can it be modified to ignore the array of names listed above?
Const shLookup As String = "Master List"
Const shSetup As String = "Received"
With Worksheets(shLookup)
aData = .Range("a1").CurrentRegion
End With
ReDim aOutput(1 To UBound(aData), 1 To 3)
For i = 2 To UBound(aData)
iCount = Evaluate("=COUNTIF('" & shSetup & "'!A:A,'" & shLookup & "'!A" & i & ")")
If aData(i, 2) <> iCount Then
n = n + 1
aOutput(n, 1) = aData(i, 1)
aOutput(n, 2) = aData(i, 2)
aOutput(n, 3) = iCount
End If
Next
EDIT
Sample worksheet data would look like this:
Master List sheet
Store EmpCount
Memphis 23
Houston 13
Phili 10
Received List Sheet
Store Region EmpName
Memphis East Joe
Memphis East James
Memphis East Jane
Memphis East Supervisor
Memphis East Manager
What I am after is to ensure that on the received list sheet there are 23 employees for Memphis, excluding the names above from the count.
EDIT 2
Per the suggestion in comments by #PKatona - it looks like I can use the CountIF() function to count the "ignore" values then subtract that count from my whole count. This syntax seems to work for one by one, however, how would I adapt it for an array?
I.E. this would give me the count for Manager but there are other buzz words I need to search for:
iIgnore = Evaluate("=COUNTIF(Range('" & shSetup & "'!A:A,'" & shLookup & "'!A" & i & "),"Manager")")

Off the top of my head without syntax checking, here's how you'd create the array of ignore values and then count them:
dim ignore() as String
ignore = Split("Manager,Supervisor,Mgr,Sup", ",")
dim ignoreCnt as integer
ignoreCnt = 0
dim aIdx as integer
for aIdx = 0 to UBound(ignore) - 1
ignoreCnt = ignoreCnt + Evaluate("=COUNTIF(Range('" & shSetup & _
"'!A:A,'" & shLookup & "'!A" & i & "),ignore(aIdx))")
next aIdx
ignoreCnt now has the total of the values you want to ignore. If you have more, just add them to the string in the Split line, the UBound function automatically gets the upper limit for the loop.

Related

Array out of bounds error Visual basic forms

Hi im new to this but my code keeps giving me the same error after ive entered three countries and their details. Once i click Ok on my third data entry i get an out of bounds error message.
here is my code if anyone can help
Dim countries(2) As employee
Dim row As Integer
For row = 0 To 2
countries(row).CountryName = InputBox("row" & row & " Enter name of country")
countries(row).population = InputBox("row" & row & " Enter population")
countries(row).Capital = InputBox("row" & row & " enter capital city")
countries(row).GDP = InputBox("row" & row & " Enter GDP value ")
countries(row).worldRanking = InputBox("row" & row & " GDP world rank")
countries(row).Democracy = InputBox("row" & row & " Democracy based? (1 = yes 2 = no")
Next row
For row = 0 To 4
If countries(row).worldRanking < 100 Then
ListBox1.Items.Add(countries(row).CountryName)
End If
Next row
You've defined a 3-element array here:
Dim countries(2) As employee
(2) = 0 to 2 = three elements.
So countries(row) where row > 2 isn't defined.
Arrays aren't always the best choice for collections. Have a look at IEnumerable, List, etc which have more flexibility (IMHO).
You could use GetUpperBound() in your loops, instead of hard-coding a number:
For row = 0 To countries.GetUpperBound(0)

Excel VBA - Expand range from using just one column to using multiple

I have a working piece of code that looks at a columns value, copies those values, and strips off the 'speed' component string of that value - Turning '200 Mbps' into just '200', etc.
They updated the source data on me and the values are now in three columns - AC, AD, AE instead of just AC now. So values can exist in either column and any row, can be Gbps and Mbps, etc.
At the end of the day, I need the total of the three columns and X number of rows. I have sample data below.
How can I (or can I even) modify this existing code to account for the extra two columns. I am wondering if the Dictionary approach is correct at this point. It was originally added at someone else's suggestion.
Dim Cla As Range
With CreateObject("scripting.dictionary")
For Each Cla In wbFrom.Sheets("Sheet0").Range("AC9", Range("AC" & Rows.Count).End(xlUp))
Cla.Value = Replace(Cla.Value, " Mbps", "")
Cla.Value = Replace(Cla.Value, " Gbps", "")
If Not .exists(Cla.Value) Then
.Add Cla.Value, Nothing
End If
Next Cla
wbTo.Sheets("Sheet1").Range("D13").Resize(.Count).Value = Application.Transpose(.keys)
End With
I don't really understand the If and With loops and how they combine with keys and Transpose like this. ((Thanks TinMan for the info))
I've tried moving this out, but having this outside the loop breaks the code. Is there something in this section that I need to update?
If Not .exists(Cla.Value) Then
.Add Cla.Value, Nothing
End If
Next Cla
Some sample data looks like this: Notice each element is on its own row.
AC AD AE
300
123
72
200
101
The 300 gets paste where it belongs but nothing else adds up or get grabbed I think. Also, when the data looks like THIS, it pastes two values instead of just one:
Notice the 300 and 123 are now on the same line, 300 gets paste into the destination cell and 123 gets paste into two cells below that.
AC AD AE
300 123
72
200
101
Example 1
Use Range.Resize() to extend the number of columns targeted.
For Each Cla In wbFrom.Sheets("Sheet0").Range("AC9", wbFrom.Sheets("Sheet0").Range("AC" & Rows.Count).End(xlUp)).Resize(, 3)
Next
Example 2
Set a helper variable to the Range and use Range.Resize() to extend the number of columns targeted.
Dim Target As Range
With wbFrom.Sheets("Sheet0")
Set Target = .Sheets("Sheet0").Range("AC9", .Range("AC" & Rows.Count).End(xlUp)).Resize(, 3)
Debug.Print Target.Address
End With
Addendum
This will strip away the " Mbps" and " Gbps" as well as insert the sum the a;; the numbers into Range("D13").
With wbFrom.Sheets("Sheet0")
Set Target = .Range("AC9", .Range("AC" & .Rows.Count).End(xlUp)).Resize(, 3)
For Each Cla In Target
Cla.Value = Replace(Cla.Value, " Mbps", "")
Cla.Value = Replace(Cla.Value, " Gbps", "")
Next Cla
.Range("D13").Value = WorksheetFunction.Sum(Target)
End With
I'm not sure that you are describing the problem correctly. Clearly, using the dictionary, get you a list of unique distinct values. But you stated that:
At the end of the day, I need the total of the three columns and X
number of rows.
The existing code leads me to believe that you are going to be doing a count of different speeds...how many 200 Mbps, how many 72 Mpbs, etc.
Either that, or the previous code didn't work as intended.
Assuming that you described the problem correctly and all you want is the total bandwidth then this should do the trick...
Dim LastRow As Long, Value As Long, Sum As Long, Count As Long
' Get the last row, looking at all 3 columns "AC:AE"
LastRow = FindLastRow(wbFrom.Sheets("Sheet0").Range("AC:AE"))
' Iterate through all 3 columns
For Each Cla In wbFrom.Sheets("Sheet0").Range("AC9:AE" & LastRow)
' Use Val() to get just the numeric value and the inline IIF() statment to automatically adjust the speed
Value = Val(Cla.Value) * IIf(InStr(Cla.Value, "Gbps") > 0, 1000, 1)
' Check if there is a Value, if so, Add it to the Sum (and increment the count)
If Value > 0 Then
Sum = Sum + Value
Count = Count + 1
End If
Next Cla
' Write the Sum to the other Workbook (not sure if you need the Count)
wbTo.Sheets("Sheet1").Range("D13") = Sum
And a function to find the last cell in a range (even if the list is filtered)
Public Function FindLastRow(r As Range) As Long
' Works on Filtered Lists/Hidden rows
Const NotFoundResult As Long = 1 ' If all cells are empty (no value, no formula), this value is returned
FindLastRow = r.Worksheet.Evaluate("IFERROR(LARGE(ROW('" & r.Worksheet.Name & "'!" & r.Address & ")*--(NOT(ISBLANK('" & r.Worksheet.Name & "'!" & r.Address & "))),1)," & NotFoundResult & ")")
End Function
From the comments on your question I gather that you want the sum of the original inputs that are contained in columns AC, AD and AE. Such sum you want to store it at cell d13. Since I have limited input, this is the least ugly code I can provide:
nRow1 = ActiveSheet.Cells(ActiveSheet.Rows.Count, "AC").End(xlUp).Row
nRow2 = ActiveSheet.Cells(ActiveSheet.Rows.Count, "AD").End(xlUp).Row
nRow3 = ActiveSheet.Cells(ActiveSheet.Rows.Count, "AE").End(xlUp).Row
nRow = Application.Max(nRow1, nRow2, nRow3)
input_range = Range("AC9:AE" & nRow)
acum = 0
For Each cell In input_range
If Not IsEmpty(cell) Then
temp = Split(cell, " ")
acum = acum + CInt(temp(0))
End If
Next
Range("D13").Value = acum

How to set a specifc name in front of the name if it matches some certain condition in another sheet

I have two sheets .
sheet-1 contains names in column A like
1) Max
2) Sam
3) Ram
sheet-2 also contains the name in column A but with some specific indicators in column B LIKE
COL"A" - 1) Max , 2) Sam, 3) Ram
COL"B" - 1 , 2, 1
so as you can see in sheet-2 i have " 1" in COL"B" in front of Max and Ram in COL"A"
using this i want to mark values in front of names in sheet-1
eg-
in sheet-2 if i have " 1" in COL"B" in front of Max and Ram in COL"A" then mark Max and Ram in sheet-1 COL"B" as "topper" and if it is 2 in case of Sam in sheet-2 mark it as average in sheet-1 COL "B" in front of Sam
is there any specific formula to do that ? i have searched but was unable to find it. it will be really helpful as i am new to this excel formulas and vba
You could use the following in B1 in sheet 1 and drag down:
=IFERROR(CHOOSE(VLOOKUP(Sheet1!A1,Sheet2!$A$1:$B$3,2,FALSE),"Topper","Average"),"")
If there were more names in lookup range extend this, Sheet2!$A$1:$B$3, to include all the additional rows.
CHOOSE function will return the item at the specified index, so if the lookup returns 1, it will return the first item in the following list i.e. "Topper". It 2 then "Average". If there was a third item it would go after "Average" etc.
The whole thing is wrapped in an IFERROR in case no matching value is found, in which case the empty string literal "" is returned; though you could specify a different return message by placing your chosen text between the "Text".
Sheet 1 formulas:
Version 2 (in sheet 1 B2 drag down):
=IFERROR(IF(VLOOKUP(Sheet1!A1,Sheet2!$A$1:$B$3,2,FALSE)=1,"Topper",IF(VLOOKUP(Sheet1!A1,Sheet2!$A$1:$B$3,2,FALSE)>4,"Weak","Average")),"")
below is the vba code for my above question and it is working great.
Sub aa()
Set Excel1 = ThisWorkbook.Sheets("Sheet1")
Set Excel2 = ThisWorkbook.Sheets("Sheet2")
Dim Excel1LR: Excel1LR = Excel1.Range("A1").CurrentRegion.Rows.Count
Dim Excel2LR: Excel2LR = Excel2.Range("A1").CurrentRegion.Rows.Count
For i = 2 To Excel1LR
Dim Value1: Value1 = Excel1.Range("A" & i).Value
For j = 2 To Excel2LR
Dim Value2: Value2 = Excel2.Range("A" & j).Value
If Value1 = Value2 Then
Dim Value3: Value3 = Excel2.Range("B" & j).Value
If Value3 = 1 Then
Excel1.Range("B" & i).Value = "topper"
ElseIf Value3 >= 2 And Value3 <= 4 Then
Excel1.Range("B" & i).Value = "average"
Else
Excel1.Range("B" & i).Value = "weak"
End If
Else
End If
Next
Next
msgbox "done"
End Sub

count repeated values in column for unique fileds

I have 2 qns that should be performed in VBA Code.
1. I want to count the total number of times a particular string has repeated for more than 40 unique values in a column.how this can be achieved.
for eg- unique values like Apple, banana, grapes (40 more unique values) are repeated in a column and I want the count of individual string like this.
Apple- 30 times repeated
banana- 4 times repeated.
after taking the total number of each strings,I want to count them with a specific criteria.
Eg- count apple, only if the cost if above 40
count grapes, only if the cost if above 40
can any1 pls help on this, how to implement this in VBA Code.
The following code adds all strings from Column A into a collection structure, sorts it while counting each unique value and stores each unique value and the corresponding sum in a dictionary structure. The results are then printed to the Immediate window. Hope this helps.
Sub main()
'variables
Dim colCollection As New Collection
Dim x, q As Variant
Dim cellValue As String
Dim j, i, count As Integer
Dim numbers As New Scripting.Dictionary 'NOTE: add microsoft scripting Runtime Ref
x = 1 'collections start at 1
While Worksheets("Sheet1").Cells(x, "A").Value <> "" 'while cell is not empty
cellValue = Worksheets("Sheet1").Cells(x, "A").Value 'store string value from cell
colCollection.Add (cellValue) ' add entry from cell to collection
x = x + 1 'increment
Wend
'Sort collection (bubbble sort) and record number of each unique item
For i = colCollection.count To 2 Step -1 'count down from collection
For j = 1 To i - 1
'bubble up item
If colCollection(j) > colCollection(j + 1) Then
colCollection.Add colCollection(j), After:=j + 1
colCollection.Remove j
End If
Next j
'finding count of unique item
If i <> colCollection.count Then 'if not at last item (can't compare 2 items when only given 1)
If i = 2 Then 'if at end
numbers.Add colCollection(i), count + 3 'add sum to dictionary with corresponding key value
Else
If StrComp(colCollection(i + 1), colCollection(i), 1) = 0 Then 'if same string
count = count + 1 'increment count
Else
numbers.Add colCollection(i + 1), count + 1 'add sum to dictionary with corresponding key value
count = 0 'reset count
End If
End If
End If
Next i
'loop through dictionary
For Each q In numbers.Keys
Debug.Print q & "- " & numbers.Item(q); " times repeated."
Next
End Sub

MS Excel 2010 - VBA to lookup in one column a customer number and Tag the corresponding column with Yes or No

I have an extremely large dataset with customer numbers and we cannot just use a =IF(E3=160248, "YES", "NO") to tag a particular customer number of 160248 with YES or NO. Instead, I would like to use VBA code to lookup Customer_Number in column E and return a YES or NO in the corresponding row in Column AG, called Incorporated_160248. I have not done an If then clause in VBA, so I have no idea where to start. Please note, each month the data set can change. One month it could be 4,000 entries and the next 3,500, so that has to be dynamic. Any thoughts?
Sub TagTryco()
Dim CN As Integer, result As String
CN = Range("E:E").Value
If CN = 160248 Then
result = "YES"
Else
result = "NO"
End If
Range("AG:AG").Value = result
End Sub
I get a Compile error: Wrong number of arguments or invalid property assignment.
This CODE Works now:
Sub TagTryco()
Dim listLength
listLength = Worksheets("ILS_Import").Cells(Rows.Count, "E").End(xlUp).Row - 1
Dim i As Integer
For i = 2 To listLength + 2
If Worksheets("ILS_Import").Range("E" & i) = 160248 Then
Worksheets("ILS_Import").Range("AG" & i) = "Yes"
Else
Worksheets("ILS_Import").Range("AG" & i) = "No"
End If
Next
End Sub
To know how many entries you have:
dim listLength
listlength = Sheet1.Cells(Rows.Count, "E").End(xlUp).Row - 1 'I assumed column E, starting at row 2
You need to loop from row 2 to the row 2 + listLength, check the cell in column E, and check if it is equal to your number:
dim i as integer
for i = 2 to listLength + 2
If Range("E" & i) = 160248 Then
Range("AG" & i) = "Yes"
Else
Range("AG" & i) = "No"
End If
Next
If you wish to scan for different numbers you can adapt the code to use a value from a cell in which you enter that number, OR use an inputbox to enter the number you want to look for, or something else. This code was not tested.
If you want to use the column name you assigned instead of AG (which is safer) you can use something along the lines of:
= Range("Incorporated_160248")(i+1)
Instead, which gives the column with an offset of i. Should bring you to the right cell.