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

Integer

Syntax

Simple Search:

    (SearchArray( {SearchVal}, {ArrayId} [, {StartIndex} ])
Extended Search:

    (SearchArray( {SearchVal}, {ArrayId} [, {ObjectId} , {MessageId} , {StartIndex} ]))

Where:

 

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 expanded 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, 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 number of times a value occurs in array, use CountArray. For a more efficient search of large arrays, use BinarySearchArray.

If a BinarySearchArray search results in -1 (not found), BinarySearchInsetPos returns the position in an array where a missing item should be inserted.

 

Custom Comparison Function for Extended Search

The developer has the option of providing a custom comparison function for the sorting 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:

You can use a single custom comparison function for a specific data type for all array functions that require one. Since SearchArray is the only array function that only requires a custom comparison function to return (EQ), while the other array functions require that a custom comparison function to return (EQ), (LT) or (GT), you should use the requirements specified in one of the other array functions (BinarySearchArray, BinarySearchInsertPos, CountArray, MinArray, MaxArray, SortArray) to design a single reusable custom comparison function.

 

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 in which the search term was found to the screen, otherwise a message stating that the string was not found is displayed. Last, the values of each array element is displayed to the screen.

// 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 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.

Syntax

(SearchArray( {SearchVal}, {ArrayId} , Desktop , (RefFunc(DFSTRICMP)) ))

This sample populates a dynamic array of strings (sCustomers), then searches it for the string "jones", no matter what the casing of any occurrence of "jones", in the sCustomers array. If the string is found, it displays the element in which the search term was found to the screen, otherwise a message stating that the string was not found is displayed. Last, the values of each array element is displayed to the screen.

This is really not a representative sample, since for an array of only 7 elements, you would use SearchArray rather than BinarySearchArray, but the sample shows you the proper syntax for this function.

// 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 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.

One way to take advantage of this is to design structs that use a unique identifier as the first member, allowing a runtime search of an array of such structs to find any struct and then access the rest of the information in that struct.

Example

This sample shows how to find the first friend with id 5 in an array filled with 10 tFriend structs.

In Procedure OnClick, MyFriends is declared as a tFriend array and populated with 10 friends' Ids and names. Another struct of type tFriend is declared to store the search value. Since the search is for a struct in an array of that struct where the first member of the struct is a simple type, a custom search function is not required.

The SearchFriend struct is filled with the value being searched for; since the search only compares the first member (iFriendId) of each struct in the array, there is no need to place values in the other members of this struct.

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 compare array values to the 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 you are looking for occurs after a known item in the array.

Example

This sample shows how to find the first result after array index 4 in an array filled with 5 result 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 4 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 are searching for a struct in a struct array and you need to find the struct using more than one struct element, you need to use the extended array search and a custom comparison function.

Example

Extended struct array search:

This sample shows how to find the first friend with last name "Jones" in an array filled with 10 tFriend structs. A custom comparison function is used to determine how array elements are compared.

Although a custom comparison function for SearchArray only needs to determine whether the 2 structs passed in are equal or not, this sample intentionally demonstrates a custom comparison function that can be reused for all array functions that use the same type and require a custom comparison function.

In Procedure OnClick, MyFriends is declared as a tFriend array and populated with 10 friends' names. Another struct of type tFriend is declared to store the search value. Since our comparison function only compares the Last member (last name) of each struct in the array, the First struct member is not filled with any value.

Struct tFriend

    String First

    String Last

End_Struct

 

// Custom comparison function:

//   Returns (GT) if struct value in first parameter > struct value in second parameter.

//   Returns (LT) if struct value in first parameter < struct value in second parameter.

//   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

Non-reusable custom comparison function:

You could also use this custom comparison function with SearchArray in the above example, but this function could not be reused for all array functions (BinarySearchArray, BinarySearchInsertPos, CountArray, MinArray, MaxArray, SortArray) that use the same type and require a custom comparison function, since it only evaluates whether the passed in structs are equal or not.

// Custom comparison function:

//   Returns (EQ) if struct value in first parameter > struct value in second parameter.

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 of unsorted string values. This creates an array as such:

    Smith Rodriguez Scott Jones

    Anderson Schmidt Verne Ricci

If the first "row" (row 0) of the array is searched, the search term "Jones" is found in element 3. If the second "row" (row 1) of the array is searched, the search term "Jones" is not found. This effectively limits the search to a specific "row" of the array.

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 real meaning and its actual sort order is undefined. The reason for sorting RowIds is it can allow faster searching when used with BinarySearchArray().