SearchArray
See also: Array Functions, CountArray, BinarySearchArray, Array Variable Assignments, Working with Arrays
Purpose
Returns the index of the first element in the array (or indicated element range) equal to a particular value, or -1 if the search was unsuccessful.
Return Type
Syntax
Simple Search:
SearchArray( {SearchVal}, {ArrayId} [, {StartIndex} ] )
Extended Search:
SearchArray( {SearchVal}, {ArrayId} [, {ObjectId}, {MessageId}, {StartIndex} ] )
Where:
-
{SearchVal}
The value to compare array elements' values to. The index of the first element whose value is equal to {SearchVal} is returned. This can be a struct with values in any number of elements to be used in a custom comparison function. -
{ArrayId}
The id of the array being searched. The array must be non-jagged and one dimensional (it can be a single dimension of a multi-dimensional array). -
{StartIndex}
The index where the search will start; matches with a lower index will not be found. -
{ObjectId}
The id of the object that implements the comparison function. -
{MessageId}
The id of the function that will be used to compare two array elements. Use (RefFunc(DFSTRICMP)) for case-insensitive string searches.
What it Does
Iterates from the first to the last element in an array and compares each element to the passed-in value {SearchVal} or uses a custom function for the comparison. The index of the first element whose value is equal to {SearchVal} is returned. If no element with a value equal to {SearchVal} is found, -1 is returned.
The simple search style lets the runtime do all the work, while the extended style requires that you create a function to do the comparison.
You can use the simple search 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 of structs, 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 its data type. This simplifies coding and allows the runtime to perform all comparisons without sending messages, which is much faster.
DataFlex implements different sorting/comparison algorithms for different data types in the runtime to provide the most efficient comparison method. To use these internal comparison algorithms, do not pass the optional ObjectId and MessageId parameters. Use these internal algorithms whenever there is no strong reason to use a custom comparison.
To determine how many times a value occurs in an array, use CountArray. For a more efficient search of large arrays, use BinarySearchArray.
If a BinarySearchArray search results in -1 (not found), BinarySearchInsertPos returns the position in an array where a missing item should be inserted.
Tip: AppendArray alternative
You can append values to the end of a dynamic array using Move and passing [-1] as the array indexer instead of using AppendArray.
Procedure Example
String[] Sentence
Move "The" to Sentence[-1]
Move "quick" to Sentence[-1]
Move "brown" to Sentence[-1]
Move "fox" to Sentence[-1]
Move "jumps" to Sentence[-1]
Move "..." to Sentence[-1]
End_Procedure
Custom Comparison Function for Extended Search
You can provide a custom comparison function for the extended search when needed (for arrays of variant and struct arrays where the search cannot use the first struct member or must search multiple struct members).
The function provided in {MessageId} must follow this syntax:
Function MyCompareFunc {array-element-type} arg1 {array-element-type} arg2 Returns Integer
This function must return one of these values:
- (EQ) — parameters are considered equal — required for SearchArray
- (GT) — first parameter is greater than second parameter — optional for SearchArray
- (LT) — first parameter is less than second parameter — optional for SearchArray
You can create a single reusable custom comparison function for a specific data type for all array functions that require one. Because SearchArray only requires a custom comparison function to return (EQ), while other array functions may require (EQ), (LT), or (GT), design your reusable comparison function using the requirements specified in one of the other array functions (BinarySearchArray, BinarySearchInsertPos, CountArray, MinArray, MaxArray, SortArray).
Simple Array Search
You can use the simple search style to search arrays of simple data types or arrays of structs where the first struct member is a simple type.
Example — String array search
This sample populates a dynamic array of strings (sCustomers), then searches it for the string "Jones". If the string is found, it displays the element index; otherwise a message is displayed.
// fires when the button is clicked
Procedure OnClick
String[] sCustomers
String sSearchTerm
Integer iSearchIndex
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]
// search for "Jones" in array
Move "Jones" to sSearchTerm
Move (SearchArray(sSearchTerm, sCustomers)) to iSearchIndex
If (iSearchIndex <> -1) Begin
Showln "The search value " sSearchTerm " was found in element " (String(iSearchIndex))
End
Else Begin
Showln "The search value " sSearchTerm " was NOT found"
End
End_Procedure
Example — Case-insensitive string array search
Searching a string array case-insensitively is common. The runtime provides a predefined case-insensitive string comparison function: DFSTRICMP, defined in the Desktop object.
Syntax:
SearchArray( {SearchVal}, {ArrayId}, Desktop, (RefFunc(DFSTRICMP)) )
Sample:
// fires when the button is clicked
Procedure OnClick
String[] sCustomers
String sSearchTerm
Integer iSearchIndex
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]
// search for "jones", in any casing, in array
Move "jones" to sSearchTerm
Move (SearchArray(sSearchTerm, sCustomers, Desktop, (RefFunc(DFSTRICMP)))) to iSearchIndex
If (iSearchIndex <> -1) Begin
Showln "The search value " sSearchTerm " was found in element " (String(iSearchIndex))
End
Else Begin
Showln "The search value " sSearchTerm " was NOT found"
End
End_Procedure
Simple Struct Array Search
You can use the simple search style for arrays of any simple data type and for arrays of structs where the first struct member is a simple data type. The runtime compares the first member of the struct automatically.
Designing structs with a unique identifier as the first member allows the runtime to find a struct quickly and then access the rest of its fields.
Example
This sample finds the first friend with id 5 in an array filled with 10 tFriend structs. Because the first member is a simple type, no custom comparison function is required.
Struct tFriend
Integer iFriendId
String First
String Last
End_Struct
Procedure OnClick
// declare array of 10 tFriend structs
tFriend[10] MyFriends
// declare tFriend struct that will hold search value(s)
tFriend SearchFriend
Integer iSearchIndex
// fill MyFriends array
Move 1 to MyFriends[0].iFriendId
Move "Janet" to MyFriends[0].First
Move "Smith" to MyFriends[0].Last
Move 2 to MyFriends[1].iFriendId
Move "Pedro" to MyFriends[1].First
Move "Rodriguez" to MyFriends[1].Last
Move 3 to MyFriends[2].iFriendId
Move "Judy" to MyFriends[2].First
Move "Smith" to MyFriends[2].Last
Move 4 to MyFriends[3].iFriendId
Move "Fred" to MyFriends[3].First
Move "Jones" to MyFriends[3].Last
Move 5 to MyFriends[4].iFriendId
Move "Martin" to MyFriends[4].First
Move "Anderson" to MyFriends[4].Last
Move 6 to MyFriends[5].iFriendId
Move "Michael" to MyFriends[5].First
Move "Schmidt" to MyFriends[5].Last
Move 7 to MyFriends[6].iFriendId
Move "Jacques" to MyFriends[6].First
Move "Verne" to MyFriends[6].Last
Move 8 to MyFriends[7].iFriendId
Move "Enrico" to MyFriends[7].First
Move "Ricci" to MyFriends[7].Last
Move 9 to MyFriends[8].iFriendId
Move "Karl" to MyFriends[8].First
Move "Sorensen" to MyFriends[8].Last
Move 10 to MyFriends[9].iFriendId
Move "Juan" to MyFriends[9].First
Move "Garcia" to MyFriends[9].Last
// Move value to comparison struct
Move 5 to SearchFriend.iFriendId
Move (SearchArray(SearchFriend, MyFriends)) to iSearchIndex
If (iSearchIndex <> -1) Begin
Showln "The search value was found in struct number " (String(iSearchIndex))
// display the values in the found struct
Showln ":" MyFriends[iSearchIndex].iFriendId ":" MyFriends[iSearchIndex].First ":" MyFriends[iSearchIndex].Last ":"
End
End_Procedure
Simple Struct Array Search with a Starting Index
You can search an array and specify a starting index if you know the result occurs after a known item in the array.
Example
This sample finds the first result after array index 4 in an array filled with 5 tResult structs.
Struct tResult
Integer iId
String sName
End_Struct
Procedure OnClick
tResult[] results
tResult searchValue
Integer iIndex
Move 4 to results[0].iId
Move "Lannister" to results[0].sName
Move 3 to results[1].iId
Move "Tyrell" to results[1].sName
Move 12 to results[2].iId
Move "Greyjoy" to results[2].sName
Move 4 to results[3].iId
Move "Targaryen" to results[3].sName
Move 2 to results[4].iId
Move "Baratheon" to results[4].sName
// search for Id = 4
Move 4 to searchValue.iId
// doing this search without a starting index returns 0
Move (SearchArray(searchValue, results)) to iIndex
// doing this search with a starting index of 3 returns 3
Move (SearchArray(searchValue, results, 3)) to iIndex
End_Procedure
Extended Struct Array Search
If you are searching for a struct in a struct array where the first struct member is NOT a simple data type, or if you need to find a struct by more than one member, use the extended array search with a custom comparison function.
Example — Extended struct array search
This sample finds the first friend with last name "Jones" in an array of tFriend structs using a custom comparison function. The comparison function shown is reusable for other array functions that require a full comparison (returns EQ, LT, GT).
Struct tFriend
String First
String Last
End_Struct
// Custom comparison function:
// Returns (GT) if Friend1.Last > Friend2.Last
// Returns (LT) if Friend1.Last < Friend2.Last
// Otherwise returns (EQ)
Function CompareFriends tFriend Friend1 tFriend Friend2 Returns Integer
If (Friend1.Last > Friend2.Last) ;
Function_Return (GT)
If (Friend1.Last < Friend2.Last) ;
Function_Return (LT)
Function_Return (EQ)
End_Function
// fires when the button is clicked
Procedure OnClick
// declare array of 10 tFriend structs
tFriend[10] MyFriends
// declare tFriend struct that will hold search value(s)
tFriend SearchFriend
Integer iSearchIndex
// Move value to compare array values to the Comparison struct
Move "Jones" to SearchFriend.Last
// 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
// call CompareFriends function to search array elements for value(s) in SearchFriend
Move (SearchArray(SearchFriend, MyFriends, Self, (RefFunc(CompareFriends)))) to iSearchIndex
Showln "The search value was found in element number " (String(iSearchIndex))
End_Procedure
Example — Non-reusable custom comparison function
You could implement a simpler, non-reusable comparison function that only checks equality. This cannot be used by other array functions that require LT/GT semantics.
// Custom comparison function:
// Returns (EQ) if both First and Last members are equal
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
Example — Searching a single dimension of a multi-dimensional array
This sample declares a 2-dimensional string array and fills it with 8 (2x4) elements. It demonstrates searching a single "row" of the array by passing that dimension (e.g., sCustomers[0]).
Procedure OnClick
String[][] sCustomers
String sSearchTerm
Integer iSearchIndex
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 "Schmidt" to sCustomers[1][1]
Move "Verne" to sCustomers[1][2]
Move "Ricci" to sCustomers[1][3]
// search for "Jones" in first "row" of array
Move "Jones" to sSearchTerm
Move (SearchArray(sSearchTerm, sCustomers[0])) to iSearchIndex
If (iSearchIndex <> -1) ;
Showln "The search value " sSearchTerm " was found in element " (String(iSearchIndex))
Else ;
Showln "The search value " sSearchTerm " was NOT found"
// search for "Jones" in second "row" of array
Move "Jones" to sSearchTerm
Move (SearchArray(sSearchTerm, sCustomers[1])) to iSearchIndex
If (iSearchIndex <> -1) Begin
Showln "The search value " sSearchTerm " was found in element " (String(iSearchIndex))
End
Else Begin
Showln "The search value " sSearchTerm " was NOT found"
End
End_Procedure
Sorting and Searching via RowId
You can search and sort on RowId. This affects SearchArray(), BinarySearchArray, CountArray, and SortArray. The sort order of RowIds has no defined meaning; its actual order is undefined. Sorting RowIds can allow faster searching when used with BinarySearchArray.