advanced programming strings arrays arguments modulus
TRANSCRIPT
Advanced Programming
StringsArrays
ArgumentsModulus
Strings are NOT arrays
• Strings have no indexes
• Although arrays of strings have indexes
• A single string variable has no index
• Array indexes can have base of 0 or 1
• Strings positions ALWAYS begin at 1
• String functions report errors for position=0
Mid() functionMyString = "Mid Function Demo" ' Create text string. FirstWord = Mid(MyString, 1, 3) ' Returns "Mid". LastWord = Mid(MyString, 14, 4) ' Returns "Demo". MidWords = Mid(MyString, 5) ' Returns "Function Demo".
InStr() function
strHaystack ="XXpXXpXXPXXP“strNeedle = "p"
intWhere = Instr(1, strHaystack, "W") Returns 0
intWhere = Instr(4, strHaystack, strNeedle) Returns 6
Other Functions
• Mid() statement (not the mid function)– strX = "Hello, Jane" ' example of mid() statement
– Mid(strX, 8, 4) = "Bill“ (creates Hello, Bill)
• Left(strX,n) and Right() – returns L/R sections
• Ucase() and Lcase() – changes Up/Low case
• Trim(), Rtrim() and Ltrim() – removes blanks
• Len() – returns number of characters
Intro to Arrays
• Lists (e.g.,states, income levels, schedules)
• Private, Public, fixed or dynamic size!
• Example:– Dim strMonthNames(0 to 11) As String
strMonth(0) = "January"
strMonth(1) = "February"
strMonth(2) = "March"
strMonth(3) = "April"
strMonth(4) = "May"
intInput = InputBox("Enter a month number (1-12)")-1
MsgBox “You entered “& strMonth(intInput)
String example: base 0
Which Array to Go?
• Option Base 1 or Option Base 0?
• Public strState(0 to 49) As String
• Public strState(1 to 50) As String
• Public strState(50) As String
Flexible Array
• Dynamic• Dim curLevel() As Currency
• Expands and contracts
• Good for uncertain run-time conditions
• Can loose contents unless…– Redim Preserve curLevel(7)
• Can erase dynamic arrays: Erase curLevel
Multidimensional arrays
• Referencing locations by field and record
• Example Dim varDataSet(0 to 4, 0 to 9)
5 fields (columns)
10 records (rows)
First field of the last record: varDataSet(0,9)
Multidimensional arrays
This array has 6 columns and 7 rows :Dim varContributor(0 to 5,0 to 6) as variant
Columns before rows (alpha order)
June Nguyen's contribution is varContributor(5,2)
Think of multidimension arrays as datasheets.
Sizing up arrays
• Your subs and functions will be more reusable if they work for any size arrays.
• Lbound(),Ubound() return lower, upper bound of one dimension, regardless of BASE.
• Lbound(varData, 1 or 2),Ubound(varData, 1 or 2)– Use 1 for fields count (columns – first again) – Use 2 for records count (rows – second again)
• How many columns are there in varData?– Ubound(varData,1) – Lbound(varData,1) + 1
Example: summarize salaries
• Dim curSalary(0 to 7, 0 to 10)• If column 7 of this array is $ salary• Summarize the salaries
For intRow = Lbound(curSalary,2) to Ubound(curSalary,2) curSum = curSum + curSalary(7, intRow)
intN = intN + 1 Next MsgBox "Total Amount=" & Format(curSum,"Currency") MsgBox "Average Amount=" & Format( _ iif(intN>0,curSum/intN,0), "Currency")
Memory Considerations
• strAbsentMinded(0 to 9) uses 22 times less memory than varAbsentMinded(1 to 10) when they hold the identical data
• intArray(0 to 9, 0 to 19, 0 to 29) reserves 6,000 integer locations, or about 12,000 (plus) bytes. 10 * 20 * 30 = 6,000 * 2 bytes/integer = 12,000 bytes
Parameter Arrays in Procs
• Extremely useful and powerful• The arguments are treated as one array• VBA forces Option Base 0, so use Lbound() and
Ubound()• Example: a general utility to calculate class
averages on quizzes, exams, and assignments after dropping your lowest score. The number of scores is unpredictable.
Parameter Arrays: ExampleFunction DropAvg(ParamArray varScore() as Variant) as Variant
Dim varAverage as Variant, varLowest as VariantDim varValue as Variant' requires at least two scores in the arrayvarLowest = 99999if UBound(varScore, 1)<= 0 then DropAvg=0 : Exit FunctionFor Each varValue in varScore
varAverage = varAverage + varValueIf varValue < varLowest then varLowest = varValueNext
DropAvg = (varAverage - varLowest) / UBound(varScore, 1)End Function Do this to test in the immediate window:
?DropAvg(95,93,87,91,81) ' notice arguments91.5?DropAvg(71,85)85
See next slide to compare Param array args to plain array args
Arrays: ExampleFunction DropAverage(dblScore() As Double) As Variant Dim varAverage As Variant, varLow As Variant Dim varValue As Variant, intI As Integer, intCount As Integer ' requires at least two scores in the array varLow = 99999 intCount = UBound(dblScore, 1) - LBound(dblScore, 1) If intCount <= 0 Then Exit Function For intI = LBound(dblScore, 1) To UBound(dblScore, 1) varAverage = varAverage + dblScore(intI) If dblScore(intI) < varLow Then varLow = dblScore(intI) Next DropAverage = (varAverage - varLow) / intCountEnd FunctionDo this to test in the immediate window:Public Sub XX() Dim dblData(0 To 2) As Double dblData(0) = 85.6: dblData(1) = 90.2: dblData(2) = 92.1 Debug.Print DropAverage(dblData) ' notice arg is an arrayEnd Sub
Creating Arrays
• The Array function• Your Option Base is observed
Option Base 0Public Function DayOfWeek(intDay As Integer) As String Dim WeekDay As Variant WeekDay = _
Array("Sun","Mon","Tue","Wed","Thu","Fri","Sat") DayOfWeek = WeekDay(intDay)End Function
In the Immediate Window?DayOfWeek(1)Mon
Creating Arrays
• The GetRows Method• Forces Option Base 0Public Function Sum() Dim intRow as Integer, intN as Integer Dim varDataSet() As Variant Dim cnn As ADODB.Connection Set cnn = CurrentProject.Connection rst.Open "tblEmployee", cnn, adOpenDynamic, , adCmdTable varDataSet = rst.GetRows rst.Close For intRow = LBound(varDataSet, 2) To UBound(varDataSet, 2) Sum = Sum + varDataSet(3, intRow) : intN = intN+1 Next Sum = iif(intN > 0,Sum/intN , 0) Debug.Print "Average Amount=" & Format( Sum, "Currency")End Function
Detecting what data is in a Variant
• VarType(variable)
• TypeName(variable)
Useful for detecting– Calculation data– Arrays (VarType=8192+)– Valid dates
Receiving Arguments
• Default is by reference (ByRef)– Send the address of the argument– The contents of the address can be changed by
either the caller or the procedure.
• Option is by value (ByVal)– Send a copy of the argument– The variable cannot be changed by the proc
because it only has a copy.
Receiving Arguments: Example
' build in the protection at design time (formal args)
Sub AllNames (ByVal BothNames as String, ByRef LastName as String, ByRef FirstName as String)
' or use this actual argument format at run time
' it forces ByVal and sends a copy of the variable
Call AllNames ((Names), First, Last)
' But, an array cannot be passed ByVal
Call Average (varDatSet, 6)
Type structure
• A named data structure
• Place in Declarations Module
• Instantiate when needed
• Result: A data object
Type ContributionFormError
FirstName As Boolean
LastName As Boolean
Date As Boolean
Party As Boolean
Sex As Boolean
Amount As Boolean
End Type
Define the structure in the Declarations Module
' create a module-level structure in
' the Declarations section of your Form Module
Private ErrorIn As ContributionFormError
' in the error checking code set these flags
ErrorIn.FirstName = True
ErrorIn.Amount = True
' example on next slide shows
1. Passing a data structure as an argument
2. Use of the With…End structure
Instantiate ErrorIn structure in the Form Module
MsgBox "The following errors must be corrected:" & vbCR & _
ErrorList(ErrorIn)",vbExclamation,"Mayor Minimum"
Function ErrorList(AnyErr As ContributionFormError) As String
With AnyErr
If .FirstName Then ErrorList = ErrorList + vbCr & "First Name"
If .LastName Then ErrorList = ErrorList + vbCr & "Last Name"
If .Party Then ErrorList = ErrorList + vbCr & "Party"
If .Sex Then ErrorList = ErrorList + vbCr & "Sex"
If .Date Then ErrorList = ErrorList + vbCr & "Date"
If .Amount Then ErrorList = ErrorList + vbCr & "Amount"
End With
End Function
Use the structure to build a message
Use the structure to build a better message
If IsError(ErrorIn) Then MsgBox "There are " & _
IsError(ErrorIn) & " errors." & vbCR & _
ErrorList(ErrorIn)",vbExclamation,"Mayor Minimum"
Private Function IsError(ErrorStructure As _ ContributionFormError) As Integer
IsError = 0 If ErrorStructure.FirstName Then IsError = IsError + 1 If ErrorStructure.LastName Then IsError = IsError + 1 If ErrorStructure.Party Then IsError = IsError + 1 If ErrorStructure.Sex Then IsError = IsError + 1 If ErrorStructure.Date Then IsError = IsError + 1 If ErrorStructure.Amount Then IsError = IsError + 1End Function
Modulus VBA and many other languages have this built in function for finding the remainder of a division. For example,
• 5 mod 2 equals 1 (5/2=2 with 1 left over)
• 6 mod 2 equals 0 (6/2=3 with 0 left over)
• anynumber mod 2 = 1 if anynumber is odd
• anynumber mod 2 = 0 if anynumber is even
Odd and even are the usual reasons for programming with mod. And there is another handy use for the function: controlling sequences by limiting the range of a counter.
Using the Modulus: Sequencing
Mod is also useful when you want to limit a series of
numbers to a range. Say you want users to be presented with
a sequence of three choices, or five choices, or seven choices
and not do a lot of programming logic.
choice = 1 + (choice mod N)
The line of code above will limit the values taken on by the
variable choice. They will be in the range of 1, 2,…, N. The
starting value of choice has to be inside the particular range.
An example is next.
Using the Modulus: Program Example
Public Sub RangeOfChoices()' initialize the variablesDim strChoice(1 to 3) As StringDim intChoice As IntegerDim intTrip As IntegerintChoice = 1strChoice(1) = "the beach?"strChoice(2) = "the mountains?"strChoice(3) = "Philadelphia?"' body of your logicDo intTrip = MsgBox("Would you like to go to " & _ strChoice(intChoice), vbYesNo, "This Summer") intChoice = (intChoice Mod 3) + 1Loop Until intTrip = vbYesEnd Sub