Skip to content

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:

  • {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

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

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.

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

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

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

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.

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.