See Also: Array Functions, Array Variable Assignments, Working with Arrays
Returns the number of array elements whose value is equal to a test value.
Simple Count:
(CountArray( {CompareVal}, {ArrayId} )
Extended Count:
(CountArray( {CompareVal}, {ArrayId}, [{ObjectId}, {MessageId}] ))
Where:
{CompareVal} is the value to compare array elements' values to. If any element's value is equal to {CompareVal}, the count to return will be incremented.
{ArrayId} is the id of the array to retrieve a range of elements from. Array must be non-jagged and one dimensional (it can be a single dimension of a multi-dimensional array).
{ObjectId} is the id of object that implements the comparison function.
{MessageId} is the id of the function that will be used to compare array elements to {CompareVal}.
Iterates through all elements in an array and compares each element to the passed in value {CompareVal} or uses a custom function for the comparison. The returned count is incremented for each matching element in the array.
The simple count style lets the runtime do all the work, while the expanded style requires that you create a function to do the comparison.
You can use the simple count style for arrays of any simple data type and arrays of structs where the first struct member is a simple data type.
If the short style of the function is used with an array, a smart comparison will be applied where the first member of the struct will be used for the comparison. Assuming that the first member is a simple data type (String, Integer, etc., not a struct or array), the search will be applied on that member based on the data type of that first member. Not only does this simplify coding, it allows the runtime to perform all comparisons without sending messages, which is much faster.
DataFlex implements different sorting algorithms for different data types in the runtime, in order to provide developers with the most efficient comparison method based on the data type. Algorithms provided in the runtime will also run faster. To use the internal comparison algorithms, simply do not pass the optional ObjectId and MessageId parameters. We recommend the use of these internal algorithms whenever there is no strong reason for a developer to use a special comparison.
To determine the element count of one or more dimensions of an array,
use SizeOfArray.
To find a specific element in an array, use SearchArray
or BinarySearchArray.
The developer has the option of providing a custom comparison function for the counting process if a custom function is desired or required (for arrays of variant and struct arrays where the search cannot use the first struct member or needs to search for multiple struct members).
The function provided in {MessageId} must follow the following syntax:
Function MyCompareFunc {array-element-type} arg1 {array-element-type} arg2 Returns Integer
This function must return one of these values:
(GT) – if first parameter is greater than second parameter
(EQ) – if parameters are (considered) equal
(LT) – if first parameter is less than second parameter
You can use a single custom comparison function for a specific data type for all array functions that require one (BinarySearchArray, BinarySearchInsertPos, CountArray, MinArray, MaxArray, SearchArray, SortArray).
You can use the simple count style to count array elements of simple data types or arrays of structs where the first struct member is a simple type.
Counting elements in an array of strings:
This sample creates a string array, then adds 10 names, 2 of them being "Smith". When CountArray is called, it returns a count of 2 for the number of array elements being equal to "Smith".
// fires when the button is clicked
Procedure OnClick
String[] sCustomers
Integer iCount
Move "Smith" to sCustomers[0]
Move "Rodriguez" to sCustomers[1]
Move "Smith" to sCustomers[2]
Move "Jones" to sCustomers[3]
Move "Anderson" to sCustomers[4]
Move "Schmidt" to sCustomers[5]
Move "Verne" to sCustomers[6]
Move "Ricci" to sCustomers[7]
Move "Sorensen" to sCustomers[8]
Move "Garcia" to sCustomers[9]
// counts the occurrence of "Smith" in sCustomers
Move (CountArray("Smith", sCustomers)) to iCount
End_Procedure
Case-insensitive count of elements in an array of strings:
Counting elements in a string array in a case-insensitive manner is a common task, so the runtime provides a predefined function for case-insensitive string comparison: DFSTRICMP, defined in the Desktop object.
(CountArray( {CompareVal}, {ArrayId} , Desktop , (RefFunc(DFSTRICMP)) ))
This sample creates a string array, then adds 10 names, 2 of them being "Smith", but using different casing. When CountArray is called, it returns a count of 2 for the number of array elements being equal to "Smith".
// fires when the button is clicked
Procedure OnClick
String[] sCustomers
Integer iCount
Move "Smith" to sCustomers[0]
Move "Rodriguez" to sCustomers[1]
Move "smith" to sCustomers[2]
Move "Jones" to sCustomers[3]
Move "Anderson" to sCustomers[4]
Move "Schmidt" to sCustomers[5]
Move "Verne" to sCustomers[6]
Move "SMITH" to sCustomers[7]
Move "Sorensen" to sCustomers[8]
Move "Garcia" to sCustomers[9]
// counts the occurrence of "smith", in any casing, in sCustomers
Move (CountArray("Smith", sCustomers, Desktop, (RefFunc(DFSTRICMP)))) to iCount
End_Procedure
You can use the simple count style for arrays of any simple data type and arrays of structs where the first struct member is a simple data type.
If the short style of the function is used with an array, a smart comparison will be applied where the first member of the struct will be used for the comparison. Assuming that the first member is a simple data type (String, Integer, etc., not a struct or array), the search will be applied on that member based on the data type of that first member. Not only does this simplify coding, it allows the runtime to perform all comparisons without sending messages, which is much faster.
This sample shows how to count the number of friends with last name "Smith"in an array filled with 10 tFriend structs.
In Procedure OnClick, MyFriends is declared as a tFriend array and populated with 10 friends' first and last names. Another struct of type tFriend is declared to store the search value (last name "Smith").
By not passing the optional ObjectId and MessageId parameters, the runtime attempts to count the array by the first struct member, which happens to be a simple type (String).
The SearchFriend struct is filled with the value being searched for; since the search only compares the first member (Last) of each struct in the array, there is no need to place values in the other members of this struct.
Struct tFriend
String Last
String First
End_Struct
Procedure OnClick
// declare array of 10 tFriend structs
tFriend[10] MyFriends
// declare tFriend struct that will hold search value
tFriend SearchFriend
Integer iCount
// fill MyFriends array
Move "Janet" to MyFriends[0].First
Move "Smith" to MyFriends[0].Last
Move "Pedro" to MyFriends[1].First
Move "Rodriguez" to MyFriends[1].Last
Move "Judy" to MyFriends[2].First
Move "Smith" to MyFriends[2].Last
Move "Fred" to MyFriends[3].First
Move "Jones" to MyFriends[3].Last
Move "Martin" to MyFriends[4].First
Move "Anderson" to MyFriends[4].Last
Move "Michael" to MyFriends[5].First
Move "Schmidt" to MyFriends[5].Last
Move "Jacques" to MyFriends[6].First
Move "Verne" to MyFriends[6].Last
Move "Enrico" to MyFriends[7].First
Move "Ricci" to MyFriends[7].Last
Move "Karl" to MyFriends[8].First
Move "Sorensen" to MyFriends[8].Last
Move "Juan" to MyFriends[9].First
Move "Garcia" to MyFriends[9].Last
// Move value to compare array values to the Comparison struct
Move "Smith" to SearchFriend.Last
Move (CountArray(SearchFriend, MyFriends)) to iCount
End_Procedure
Extended struct array count:
This sample uses a custom comparison function to count how many friends with last name "Smith" and first name "Judy" are in an array of tFriend structs.
Since this example does a comparison of 2 struct members, simple search cannot be used and a custom comparison function must be used instead.
The custom comparison function (CompareFriends) returns EQ only if both the First and Last members of the tFriend struct passed in as the first parameter to the function are equal to the First and Last members of the tFriend struct passed in as the second parameter.
You can make the custom comparison function as complex as you need, as long as it returns EQ, LT or GT to the CountArray call.
In Procedure OnClick, MyFriends is declared as a array of tFriend and populated with friends' names. Another struct of type tFriend is declared to store the comparison value.
The result in iCount will be 1 using the data in this sample.
Struct tFriend
String First
String Last
End_Struct
// Custom comparison function:
Function CompareFriends tFriend Friend1 tFriend Friend2 Returns Integer
If ((Friend1.Last = Friend2.Last) and (Friend1.First = Friend2.First)) Begin
Function_Return (EQ)
End
End_Function
Procedure OnClick
// declare array of tFriend structs
tFriend[] MyFriends
// declare tFriend struct that will hold comparison value(s)
tFriend CompareFriend
Integer iCount
// fill MyFriends array
Move "Janet" to MyFriends[0].First
Move "Smith" to MyFriends[0].Last
Move "Pedro" to MyFriends[1].First
Move "Rodriguez" to MyFriends[1].Last
Move "Judy" to MyFriends[2].First
Move "Smith" to MyFriends[2].Last
Move "Fred" to MyFriends[3].First
Move "Jones" to MyFriends[3].Last
Move "Martin" to MyFriends[4].First
Move "Anderson" to MyFriends[4].Last
Move "Michael" to MyFriends[5].First
Move "Schmidt" to MyFriends[5].Last
Move "Jacques" to MyFriends[6].First
Move "Verne" to MyFriends[6].Last
Move "Enrico" to MyFriends[7].First
Move "Ricci" to MyFriends[7].Last
Move "Karl" to MyFriends[8].First
Move "Sorensen" to MyFriends[8].Last
Move "Juan" to MyFriends[9].First
Move "Garcia" to MyFriends[9].Last
// Move value to compare array values to the Comparison struct
Move "Smith" to CompareFriend.Last
Move "Judy" to CompareFriend.First
// call CompareFriends function to count array elements that match value(s) in CompareFriend
Move (CountArray(CompareFriend, MyFriends, Self, (RefFunc(CompareFriends)))) to iCount
End_Procedure
Counting a single dimension of a multi-dimensional array:
This sample declares a 2 dimensional string array and fills it with 8 (2x4) elements of unsorted string values. This creates an array as such:
Smith Rodriguez Scott Jones
Anderson Smith Verne Ricci
The number of occurrences of "Smith" in the first "row" (row 0) of the array is counted and displayed, then the second "row" (row 1). Last, the total count is displayed.
Procedure OnClick
String[][] sCustomers
Integer iCount0 iCount1
Move "Smith" to sCustomers[0][0]
Move "Rodriguez" to sCustomers[0][1]
Move "Scott" to sCustomers[0][2]
Move "Jones" to sCustomers[0][3]
Move "Anderson" to sCustomers[1][0]
Move "Smith" to sCustomers[1][1]
Move "Verne" to sCustomers[1][2]
Move "Ricci" to sCustomers[1][3]
Move (CountArray("Smith",sCustomers[0])) to iCount0
showln "Count in first row of array: " (string(iCount0))
Move (CountArray("Smith",sCustomers[1])) to iCount1
showln "Count in second row of array: " (string(iCount1))
showln "Count in full array: " (string(iCount0+iCount1))
End_Procedure
You can search and sort on RowId. This affects SearchArray(), BinarySearchArray(), CountArray()and SortArray(). The sort order of RowIds has no real meaning and its actual sort order is undefined. The reason for sorting RowIds is it can allow faster searching when used with BinarySearchArray().