SortArray
See Also: Array Functions, Array Variable Assignments, Working with Arrays
Purpose
Returns an array with sorted elements.
Return Type
Syntax
Simple Sort:
SortArray({ArrayId} [, {bLinguistic}])
Extended Sort:
SortArray({ArrayId} [, {ObjectId}, {MessageId}])
Parameters
-
{ArrayId}: The ID of the array being sorted. The array must be non-jagged and one-dimensional (it can be a single dimension of a multi-dimensional array).
-
{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.
-
{bLinguistic} (optional): Indicates that a linguistic comparison is performed according to the localization rules configured by DF_LOCALE_CODE. Read more in the Binary vs Linguistic section below.
What it Does
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 extended style requires that you create a function to perform the comparison.
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 simple sort style 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. This simplifies coding and 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 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 using these internal algorithms whenever there is no strong reason for a developer to use a special comparison.
Binary vs Linguistic
For comparing strings, DataFlex implements two styles of comparisons. By default (when the second parameter bLinguistic is not passed or is set to True), a linguistic comparison is performed 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 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.
Custom Comparison Function for Extended Sort
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 the first parameter is greater than the second parameter
- (EQ): if the parameters are considered equal
- (LT): if the first parameter is less than the 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).
Simple Array Sort
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.
Example
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
Example
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.
Syntax
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
Simple Struct Array Sort
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 simple sort style 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. This simplifies coding and allows the runtime to perform all comparisons without sending messages, which is much faster.
Example
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
Example
Extended Struct Array Sort:
This sample declares a structured data type (tUSAddress), then declares two 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 sort 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) 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 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
Example
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 in second parameter.
// Returns (GT) if ZipCode member value in first parameter > ZipCode member value in second parameter.
// Returns (LT) if Street member value in first parameter < Street member value in second parameter.
// Returns (GT) if Street member value in first parameter > Street member 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
Example
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
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 that it can allow faster searching when used with BinarySearchArray().
Notes
-
What is the complexity of the DataFlex SortArray function (where n is the 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.
-