See Also: Array Functions, Array Variable Assignments, Working with Arrays
Returns array with sorted elements.
Simple Sort:
(SortArray( {ArrayId} [, {bLinguistic} ] ) )
Extended Sort:
(SortArray( {ArrayId} [, {ObjectId} , {MessageId} ] )
Where:
{ArrayId} is the id of the array being sorted. 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 2 array elements.
{bLinguistic] (optional) means that a linguistic comparison is done according to the localization rules configured by DF_LOCALE_CODE. Read more in the Binary vs Linguistic section below.
SortArray sorts an array using either an internal sorting algorithm or one provided by the developer.
The simple sort 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 comparison 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.
For comparing strings DataFlex implements two styles of comparisons. By default (second parameter bLinguistic is not passed or True) a linguistic comparison is done according to the localization rules configured by DF_LOCALE_CODE. This results in a logical sorting order for humans. When sorting for the computer (for example to be able to quickly find items using BinarySearchArray) it is recommended to use the binary comparison method that simply compares the individual code units. This is done by passing false as the second parameter. The resulting order might not be logical for humans (extended characters might be located in strange places) but makes perfect sense to computers.
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:
(GT) – if first parameter is greater than second parameter
(EQ) – if parameters order 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 sort style to sort arrays of simple data types or arrays of structs where the first struct member is a simple type.
String array sort:
This sample sorts a dynamic array of strings (sCustomers), then displays the sorted array to the screen.
The code that populates the sCustomers array is not shown for the sake of simplicity and clarity.
// fires when the button is clicked
Procedure OnClick
String[] sCustomers
// populate sCustomers with customer data
// :
// sort the array
Move (SortArray(sCustomers)) to sCustomers
End_Procedure
Case-insensitive string array sort:
Sorting 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.
(SortArray( {ArrayId} , Desktop , (RefFunc(DFSTRICMP)) ))
This sample sorts a dynamic array of strings (sCustomers) in a case-insensitive manner, then displays the sorted array to the screen.
The code that populates the sCustomers array is not shown for the sake of simplicity and clarity.
// fires when the button is clicked
Procedure OnClick
String[] sCustomers
Integer i iArrayCount
// populate sCustomers with customer data
// :
// sort the array in a case-insensitive manner
Move (SortArray(sCustomers, Desktop, (RefFunc(DFSTRICMP)))) to sCustomers
// display the sorted array
Move (SizeOfArray(sCustomers)) to iArrayCount
For i From 0 to (iArrayCount-1)
showln sCustomers[i]
Loop
End_Procedure
You can use the simple sort 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 sort 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 sort an array of friends by last name.
This sample sorts an array of structs by last name, by simply making last name the first member of the struct. By not passing the optional ObjectId and MessageId parameters, the runtime attempts to sort the array by the first struct member, which happens to be a simple type (String).
Struct tFriend
String Last
String First
End_Struct
Procedure OnClick
// declare array of tFriend structs
tFriend[] MyFriends
// 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 (SortArray(MyFriends)) to MyFriends
End_Procedure
Extended struct array sort:
This sample declares a structured data type (tUSAddress), then declares 2 arrays of type tUSAddress. The first array (myAddresses) is populated, then sorted, and the result placed in the second array (mySortedAddresses), the contents of which are displayed to the screen. A custom comparison function is used to determine how array elements are compared.
Since this example does a comparison of the second struct member, not the first, simple search cannot be used and a custom comparison function must be used instead.
This sample is somewhat contrived, since the obvious solution to make this particular sort more efficient would be to simply make ZipCode the first struct member, but the point is to demonstrate how to use a custom function for sorting.
You can make the custom comparison function as complex as you need, as long as it returns EQ, LT or GT to the SortArray call.
Struct tUSAddress
String Street
Integer ZipCode
End_Struct
// Custom comparison function:
// Returns (GT) struct value in first parameter > struct value in second parameter.
// Returns (LT) struct value in first parameter < struct value in second parameter.
// Otherwise returns (EQ).
Function CompareAddresses tUSAddress Address1 tUSAddress Address2 Returns Integer
If (Address1.ZipCode > Address2.ZipCode) ;
Function_Return (GT)
If (Address1.ZipCode < Address2.ZipCode) ;
Function_Return (LT)
Function_Return (EQ)
End_Function
// fires when the button is clicked
Procedure OnClick
tUSAddress[] myAddresses mySortedAddresses
// initialize address array
Move 33186 to myAddresses[0].ZipCode
Move "14001 SW 119 Ave" to myAddresses[0].Street
Move 33186 to myAddresses[1].ZipCode
Move "14000 SW 119 Ave" to myAddresses[1].Street
Move 78664 to myAddresses[2].ZipCode
Move "514 Paladin Place" to myAddresses[2].Street
Move 78664 to myAddresses[3].ZipCode
Move "504 Dinge Bay" to myAddresses[3].Street
Move 78664 to myAddresses[4].ZipCode
Move "504 Paladin Place" to myAddresses[4].Street
Move (SortArray(myAddresses, Self, (RefFunc(CompareAddresses)))) to mySortedAddresses
End_Procedure
Struct array sort sorting multiple members:
This sample is identical to the example directly above, with the exception that it sorts the addresses first by zip code and then by street address, so that street addresses are sorted by street address inside each batch of sorted zip codes.
The only code change required for this is to add a second set of conditional statements to the custom sort function that compares the street addresses the same way as the zip codes. This function tests the ZipCode and Street members in the arrays in order of precedence.
// Custom comparison function:
// Returns (LT) if ZipCode member value in first parameter < ZipCode member value value in second parameter.
// Returns (GT) if ZipCode member value in first parameter > ZipCode member value value in second parameter.
// Returns (LT) if Street member value in first parameter < Street member value value in second parameter.
// Returns (GT) if Street member value in first parameter < Street member value value in second parameter.
// Otherwise returns (EQ).
Function CompareAddresses tUSAddress Address1 tUSAddress Address2 Returns Integer
// sort first by zip code
If (Address1.ZipCode > Address2.ZipCode) ;
Function_Return (GT)
If (Address1.ZipCode < Address2.ZipCode) ;
Function_Return (LT)
// sort second by street address
If (Address1.Street > Address2.Street) ;
Function_Return (GT)
If (Address1.Street < Address2.Street) ;
Function_Return (LT)
Function_Return (EQ)
End_Function
Sorting a single dimension of a multi-dimensional array:
This sample declares a 2 dimensional integer array and fills it with 9 (3x3) elements of unsorted integer values. This creates an array as such:
7 5 2
4 6 1
9 7 2
The first "row" (row 0) of the array is then sorted and placed in row 0 of the resulting array (in this sample, the results of SortArray are placed back in the original array), resulting in this array:
2 5 7
4 6 1
9 7 2
Procedure OnClick
Integer[][] myInts
Move 7 to myInts[0][0]
Move 5 to myInts[0][1]
Move 2 to myInts[0][2]
Move 4 to myInts[1][0]
Move 6 to myInts[1][1]
Move 1 to myInts[1][2]
Move 9 to myInts[2][0]
Move 7 to myInts[2][1]
Move 2 to myInts[2][2]
Move (SortArray(myInts[0])) to myInts[0]
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().
What is the complexity of the DataFlex SortArray function (where n is number of array elements)?
a) Using internal logic:
Sorting data type string uses O(n), in other words, linear time, and requires additional memory for n-string pointers. The algorithm is stable (equal elements are in the order in which they were in the unsorted array). Based on MSD RadixSort.
Sorting data types bigint, char, currency, date, datetime, decimal, dword, integer, number, short, ubigint, uchar, uinteger and ushort is done in linear time and requires additional memory of the array size. Based on LSD RadixSort.
Sorting data types Boolean, float, real, time and timespan uses O(n log n) time complexity, it is in place (no additional memory required) and not stable. Based on QSort.
b) Using a developer supplied comparison method:
Sorting is O(n log n) time complexity, it is in place and not stable. Based on QSort.