QSORT statement

Purpose:

QSORT sorts an array or a portion of an array. The array data type can be integer, single or double floating point or string.

👉 The default QSORT of strings is case insensitive, that is, 'A' is equal to 'a'.

Syntax 1:

QSORT Array, _
 Elements AS INTEGER _
 [, ASCENDING or DESCENDING] _
 [, NATURAL] _
 [, SENSITIVE ]

Parameters:

  • Data type: Scalar
    Array STATIC string or numeric array. A sigil must be appended to the array identifier, % for integer, ! for single, # for double or $ for string, to indicate the data type of the array. For example
    ArrayInteger%
    ArraySingle!
    ArrayDouble#
    ArrayString$
    
    Do not include the array size brackets [ ] when specifying the Array name.
  • Data type: INTEGER
    Elements Number of elements to sort counting from element [0], the first element in the array.
  • Data type: Argument
    ASCENDING or DESCENDING [OPTIONAL] The sort order. Default is ASCENDING order.
  • Data type: Argument
    NATURAL [OPTIONAL] The sort will be alphanumeric.
  • Data type: Argument
    SENSITIVE [OPTIONAL] The sort will be case SENSITIVE , that is, 'A' is not equal to 'a'.

Syntax 2:

QSORT DYNAMIC Array, _
 Elements AS INTEGER _
 [, ASCENDING or DESCENDING] _
 [, NATURAL] _
 [, SENSITIVE ]

Parameters:

  • Data type: Scalar
    Array DYNAMIC string or numeric array. A sigil must be appended to the array identifier, % for integer, ! for single, # for double or $ for string, to indicate the data type of the array. For example
    ArrayInteger%
    ArraySingle!
    ArrayDouble#
    ArrayString$
    
    Do not include the array size brackets [ ] when specifying the Array name.
  • Data type: INTEGER
    Elements Number of elements to sort counting from element [0], the first element in the array.
  • Data type: Argument
    ASCENDING or DESCENDING [OPTIONAL] The sort order. Default is ASCENDING order.
  • Data type: Argument
    NATURAL [OPTIONAL] The sort will be alphanumeric.
  • Data type: Argument
    SENSITIVE [OPTIONAL] The sort will be case SENSITIVE , that is, 'A' is not equal to 'a'.

Example 1:

Static array.

DIM UpperLimit
SET Buff$[]
  "AAAA",
  "dddd",
  "CCCC",
  "bbbb",
  "aaaa",
  "cccc",
  "BBBB",
  "DDDD"
END SET

UpperLimit = UBOUND(Buff) + 1

QSORT Buff$, UpperLimit
CALL PrintTheBuff

QSORT Buff$, UpperLimit, SENSITIVE
PrintTheBuff()

QSORT Buff$, UpperLimit, ASCENDING
CALL PrintTheBuff

QSORT Buff$, UpperLimit, ASCENDING, SENSITIVE
PrintTheBuff()

QSORT Buff$, UpperLimit, DESCENDING
CALL PrintTheBuff

QSORT Buff$, UpperLimit, DESCENDING, SENSITIVE
PrintTheBuff()


SUB PrintTheBuff()
  DIM Aye
  WHILE Aye < UpperLimit
    IF Buff$[Aye] > "" THEN PRINT Buff$[Aye]
    INCR Aye
  WEND
  ? 
END SUB

Result:

aaaa
AAAA
bbbb
BBBB
cccc
CCCC
DDDD
dddd

AAAA
BBBB
CCCC
DDDD
aaaa
bbbb
cccc
dddd

aaaa
AAAA
bbbb
BBBB
cccc
CCCC
dddd
DDDD

AAAA
BBBB
CCCC
DDDD
aaaa
bbbb
cccc
dddd

DDDD
dddd
CCCC
cccc
bbbb
BBBB
aaaa
AAAA

dddd
cccc
bbbb
aaaa
DDDD
CCCC
BBBB
AAAA

Example 2:

Dynamic array.

DIM DYNAMIC Buf$[10]

Buf$[0] = "AAAA"
Buf$[1] = "dddd"
Buf$[2] = "CCCC"
Buf$[3] = "bbbb"
Buf$[4] = "aaaa"
Buf$[5] = "cccc"
Buf$[6] = "BBBB"
Buf$[7] = "DDDD"

CALL Foo(Buf$)
? 
CALL Foo2(Buf$)
? 
CALL Foo3(Buf$)
? 
CALL Foo4(Buf$)
? 
CALL Foo5(Buf$)
? 
CALL Foo6(Buf$)


SUB Foo(A$ AS STRARRAY)
  LOCAL i
  QSORT DYNAMIC A$, 9
  WHILE ISPTR(A$[i])
    IF A$[i] > "" THEN PRINT A$[i]
    INCR i
  WEND
END SUB

SUB Foo2(A$ AS STRARRAY)
  LOCAL i
  QSORT DYNAMIC A$, 9, SENSITIVE
  WHILE ISPTR(A$[i])
    IF A$[i] > "" THEN PRINT A$[i]
    INCR i
  WEND
END SUB

SUB Foo3(A$ AS STRARRAY)
  LOCAL i
  QSORT DYNAMIC A$, 9, ASCENDING
  WHILE ISPTR(A$[i])
    IF A$[i] > "" THEN PRINT A$[i]
    INCR i
  WEND
END SUB

SUB Foo4(A$ AS STRARRAY)
  LOCAL i
  QSORT DYNAMIC A$, 9, ASCENDING, SENSITIVE
  WHILE ISPTR(A$[i])
    IF A$[i] > "" THEN PRINT A$[i]
    INCR i
  WEND
END SUB

SUB Foo5(A$ AS STRARRAY)
  LOCAL i
  QSORT DYNAMIC A$, 9, DESCENDING
  WHILE ISPTR(A$[i])
    IF A$[i] > "" THEN PRINT A$[i]
    INCR i
  WEND
END SUB

SUB Foo6(A$ AS STRARRAY)
  LOCAL i
  QSORT DYNAMIC A$, 9, DESCENDING, SENSITIVE
  WHILE ISPTR(A$[i])
    IF A$[i] > "" THEN PRINT A$[i]
    INCR i
  WEND
END SUB

Result:

aaaa
AAAA
bbbb
BBBB
cccc
CCCC
DDDD
dddd

AAAA
BBBB
CCCC
DDDD
aaaa
bbbb
cccc
dddd

aaaa
AAAA
bbbb
BBBB
cccc
CCCC
DDDD
dddd

AAAA
BBBB
CCCC
DDDD
aaaa
bbbb
cccc
dddd

DDDD
dddd
CCCC
cccc
bbbb
BBBB
aaaa
AAAA

dddd
cccc
bbbb
aaaa
DDDD
CCCC
BBBB
AAAA

Example 3:

CLS

GLOBAL I

SET A![9]
  5.1, 3, 1.2674, 5.7345, 8, 5.2, 9, 5.56, 7.77
END SET

QSORT A!, 9, ASCENDING

FOR I = 0 TO 8
  PRINT A![I]
NEXT

PRINT

SET B$[9]
  " B", " D", " A", " H", " G", " F", " I", " C", " E"
END SET

QSORT B$, 9, DESCENDING

FOR I = 0 TO 8
  PRINT B$[I]
NEXT

PRINT

SET C$[9]
  "000.txt",
  "0A0.txt",
  "003.txt",
  "020.txt",
  "0A1.txt",
  "100.txt",
  "0A2.txt",
  "033.txt",
  "024.txt"
END SET

QSORT C$, 9, ASCENDING

FOR I = 0 TO 8
  PRINT C$[I]
NEXT

PRINT

SET D$[9]
  "000.txt",
  "0A0.txt",
  "003.txt",
  "020.txt",
  "0A1.txt",
  "100.txt",
  "0A2.txt",
  "033.txt",
  "024.txt"
END SET

QSORT D$, 9, ASCENDING, NATURAL

FOR I = 0 TO 8
  PRINT D$[I]
NEXT

Result:

 1.2674
 3
 5.1
 5.2
 5.56
 5.7345
 7.77
 8
 9

 I
 H
 G
 F
 E
 D
 C
 B
 A

000.txt
003.txt
020.txt
024.txt
033.txt
0A0.txt
0A1.txt
0A2.txt
100.txt

0A0.txt
0A1.txt
0A2.txt
000.txt
003.txt
020.txt
024.txt
033.txt
100.txt

Example 4:

This example sorts a portion of the array, the first 4 elements.

DIM UpperLimit
SET Buff$[]
 "A",
 "D",
 "C",
 "B",
 "F",
 "H",
 "E",
 "G"
END SET

UpperLimit = UBOUND(Buff) + 1

QSORT Buff$, 4
CALL PrintTheBuff

QSORT Buff$, UpperLimit
CALL PrintTheBuff


SUB PrintTheBuff ()
 DIM Aye
 WHILE Aye < UpperLimit
  IF Buff$[Aye] > "" THEN PRINT Buff$[Aye]
  INCR Aye
 WEND
 ?
END SUB

Result:

A
B
C
D
F
H
E
G

A
B
C
D
E
F
G
H

QSORTIDX statement

Purpose:

QSORTIDX will sort, very quickly, a table of data arrays.

Syntax 1: Simple array

QSORTIDX IndexArray AS INTEGER, NumRecs AS INTEGER, ArrayToSort AS STRING, KeyField

Parameters:

  • Data type: INTEGER
    IndexArray STATIC or DYNAMIC (single dimension) integer array that is to be sorted and is used to reference ArrayToSort. Note that IndexArray is automatically initialized before being sorted.
  • Data type: INTEGER
    NumRecs Number of records contained in ArrayToSort.
  • Data type: STRING
    ArrayToSort can be
    1. a two dimension DYNAMIC string array with the first dimension being the number of fields, the second dimension being the number of records.

      For example, when ArrayToSort is declared as

      DIM DYNAMIC ArrayToSort$[3, 1000]
      

      a two dimensional array is created which can store three fields with each field containing space for one thousand items (strings in this instance) each with a default length of 2048 bytes.

      or

    2. If you wish to specify a custom cell length, you can do so by adding a third argument when declaring the ArrayToSort which in this case is a three dimension DYNAMIC string array with the first dimension being the number of fields, the second dimension being the number of records, and the third dimension the custom cell length. An appended data type specifier, AS CHAR, is also required.

      Adding a third argument, 32, to the example above, like this,

      DIM DYNAMIC ArrayToSort[3, 1000, 32] AS CHAR
      

      would create a two dimensional array which can store three fields with each field containing space for one thousand, 32 byte custom length, string items.

  • Data type: Identifier
    KeyField The name of the field (element) in ArrayToSort to be sorted.

Remarks:

Example 1:

MACRO  GivenName = 0
MACRO  Surname   = 1
MACRO  Age       = 2
MACRO  Address   = 3
MACRO  City   = 4
MACRO  State  = 5
MACRO  Zip    = 6
MACRO  Income = 7
MACRO  NumRecs = 3
MACRO  LastRec = NumRecs - 1

DIM RecData$[8]
RecData[0] = "GivenName"
RecData[1] = "Surname"
RecData[2] = "Age"
RecData[3] = "Address"
RecData[4] = "City"
RecData[5] = "State"
RecData[6] = "Zip Code"
RecData[7] = "Income"
 
DIM i%
  
DIM DYNAMIC Idx[NumRecs]
  
DIM DYNAMIC ContactAry1$[8, NumRecs, 32] AS CHAR
'8 fields(32 chars each), 3 records

ContactAry1$[GivenName, 0] = "Katrina"
ContactAry1$[Surname, 0] = "Van Tassel"
ContactAry1$[Age, 0]      = "16"
ContactAry1$[Address, 0] = "18 North Broadway"
ContactAry1$[City, 0]     = "Sleepy Hollow"
ContactAry1$[State, 0]    = "N.Y."
ContactAry1$[Zip, 0]      = "10591-1806"
ContactAry1$[Income, 0]   = "1500250.98"
 
ContactAry1$[GivenName, 1] = "Ichabod"
ContactAry1$[Surname, 1] = "Crane"
ContactAry1$[Age, 1]      = "48"
ContactAry1$[Address, 1] = "Route 9H"
ContactAry1$[City, 1]     = "Kinderhook"
ContactAry1$[State, 1]    = "NY"
ContactAry1$[Zip, 1]      = "12106"
ContactAry1$[Income, 1]   = "     40.96"
 
ContactAry1$[GivenName, 2] = "Abraham 'Brom Bones'"
ContactAry1$[Surname, 2] = "Van Brunt"
ContactAry1$[Age, 2]      = "19"
ContactAry1$[Address, 2] = "540 North Broadway"
ContactAry1$[City, 2]     = "North Tarrytown"
ContactAry1$[State, 2]    = "New York"
ContactAry1$[Zip, 2]      = "10591"
ContactAry1$[Income, 2]   = "  50025.98"
 
CALL SortAndPrint(0)
CALL SortAndPrint(1)
CALL SortAndPrint(2)
CALL SortAndPrint(3)
CALL SortAndPrint(4)
CALL SortAndPrint(5)
CALL SortAndPrint(6)
CALL SortAndPrint(7)

SUB SortAndPrint (field)

  SELECT CASE field
    CASE 0
    QSORTIDX Idx, 3, ContactAry1, GivenName
    CASE 1
    QSORTIDX Idx, 3, ContactAry1, Surname
    CASE 2
    QSORTIDX Idx, 3, ContactAry1, Age
    CASE 3
    QSORTIDX Idx, 3, ContactAry1, Address
    CASE 4
    QSORTIDX Idx, 3, ContactAry1, City
    CASE 5
    QSORTIDX Idx, 3, ContactAry1, State
    CASE 6
    QSORTIDX Idx, 3, ContactAry1, Zip
    CASE 7
    QSORTIDX Idx, 3, ContactAry1, Income
  END SELECT

  FOR i% = 0 TO LastRec
    PRINT "Record ", i%, " sorted by key ", RecData$[field]
    PRINT "GivenName: ", ContactAry1$[GivenName, Idx[i]]
    PRINT "  Surname: ", ContactAry1$[Surname, Idx[i]]
    PRINT "      Age: ", ContactAry1$[Age, Idx[i]]
    PRINT "  Address: ", ContactAry1$[Address, Idx[i]]
    PRINT "     City: ", ContactAry1$[City, Idx[i]]
    PRINT "    State: ", ContactAry1$[State, Idx[i]]
    PRINT " Zip Code: ", ContactAry1$[Zip, Idx[i]]
    PRINT "   Income: ", ContactAry1$[Income, Idx[i]]
    PRINT " "
  NEXT i%
END SUB

Syntax 2: User defined type records with an index array.

QSORTIDX IndexArray AS INTEGER, NumRecs AS INTEGER, UDT.MemberToSort, DataKey AS INTEGER

Parameters:

  • Data type: INTEGER
    IndexArray DYNAMIC (single dimension) integer array that is to be sorted and used to reference the UDT.MemberToSort array. Note that IndexArray is automatically initialized before being sorted.
  • Data type: INTEGER
    NumRecs number of records contained in the UDT.MemberToSort array.
  • Data type: Identifier
    UDT.MemberToSort specifies the user defined type array member by which the sort is to be made.
  • Data type: INTEGER
    DataKey indicates the data type. 0 - STRING, 1 - INTEGER, 2 - DOUBLE, 3 - UINT

Example 2:

TYPE MyRecord
  GivenName[50] AS CHAR
  Surname[50] AS CHAR
  Age AS INTEGER
  Address[100] AS CHAR
  City[100] AS CHAR
  State[30] AS CHAR
  Zip[15] AS CHAR
  Income AS DOUBLE
END TYPE

DIM RecData$[8]
RecData[0] = "GivenName"
RecData[1] = "Surname"
RecData[2] = "Age"
RecData[3] = "Address"
RecData[4] = "City"
RecData[5] = "State"
RecData[6] = "Zip Code"
RecData[7] = "Income"

DIM NumRecs% = 3
DIM LastRec%
LastRec% = NumRecs - 1

GLOBAL DYNAMIC Addr[NumRecs] AS MyRecord
GLOBAL DYNAMIC Idx[NumRecs]

Addr[0].GivenName$ = "Katrina"
Addr[0].Surname$   = "Van Tassel"
Addr[0].Age%       = 16
Addr[0].Address$   = "18 North Broadway"
Addr[0].City$      = "Sleepy Hollow"
Addr[0].State$     = "N.Y."
Addr[0].Zip$       = "10591-1806"
Addr[0].Income#    = 1500250.98

Addr[1].GivenName$ = "Ichabod"
Addr[1].Surname$   = "Crane"
Addr[1].Age%       = 48
Addr[1].Address$   = "Route 9H"
Addr[1].City$      = "Kinderhook"
Addr[1].State$     = "NY"
Addr[1].Zip$       = "12106"
Addr[1].Income#    = 40.96
                   
Addr[2].GivenName$ = "Abraham 'Brom Bones'"
Addr[2].Surname$   = "Van Brunt"
Addr[2].Age%       = 19
Addr[2].Address$   = "540 North Broadway"
Addr[2].City$      = "North Tarrytown"
Addr[2].State$     = "New York"
Addr[2].Zip$       = "10591"
Addr[2].Income#    = 50025.98

CALL SortAndPrint(0)
CALL SortAndPrint(1)
CALL SortAndPrint(2)
CALL SortAndPrint(3)
CALL SortAndPrint(4)
CALL SortAndPrint(5)
CALL SortAndPrint(6)
CALL SortAndPrint(7)

SUB SortAndPrint (field)

  SELECT CASE field
    CASE 0
    QSORTIDX Idx, 3, Addr.GivenName, 0
    CASE 1
    QSORTIDX Idx, 3, Addr.Surname, 0
    CASE 2
    QSORTIDX Idx, 3, Addr.Age, 1
    CASE 3
    QSORTIDX Idx, 3, Addr.Address, 0
    CASE 4
    QSORTIDX Idx, 3, Addr.City, 0
    CASE 5
    QSORTIDX Idx, 3, Addr.State, 0
    CASE 6
    QSORTIDX Idx, 3, Addr.Zip, 0
    CASE 7
    QSORTIDX Idx, 3, Addr.Income, 2
  END SELECT

  FOR INTEGER i% = 0 TO LastRec
    PRINT "Record ", i%, " sorted by key ", RecData$[field]
    PRINT "GivenName: ", Addr[Idx[i]].GivenName$
    PRINT "  Surname: ", Addr[Idx[i]].Surname$
    PRINT "      Age: ", Addr[Idx[i]].Age%
    PRINT "  Address: ", Addr[Idx[i]].Address$
    PRINT "     City: ", Addr[Idx[i]].City$
    PRINT "    State: ", Addr[Idx[i]].State$
    PRINT " Zip Code: ", Addr[Idx[i]].Zip$
    PRINT "   Income: ", Addr[Idx[i]].Income#
    PRINT " "
  NEXT i%
END SUB

Syntax 3: User defined type records without an index array.

QSORTIDX 0, NumRecs AS INTEGER, UDT.MemberToSort, DataKey AS INTEGER

Parameters:

  • Data type: INTEGER
    IndexArray is set to 0.
  • Data type: INTEGER
    NumRecs The number of records contained in the UDT.MemberToSort array.
  • Data type: Identifier
    UDT.MemberToSort The user defined type array member by which the sort is to be made.
  • Data type: INTEGER
    DataKey The data type. 0 - STRING, 1 - INTEGER, 2 - DOUBLE, 3 - UINT

Example 3:

TYPE MyRecord
  GivenName[50] AS CHAR
  Surname[50] AS CHAR
  Age AS INTEGER
  Address[100] AS CHAR
  City[100] AS CHAR
  State[30] AS CHAR
  Zip[15] AS CHAR
  Income AS DOUBLE
END TYPE

DIM RecData$[8]
RecData[0] = "GivenName"
RecData[1] = "Surname"
RecData[2] = "Age"
RecData[3] = "Address"
RecData[4] = "City"
RecData[5] = "State"
RecData[6] = "Zip Code"
RecData[7] = "Income"

DIM NumRecs% = 3
DIM LastRec%
LastRec% = NumRecs - 1

GLOBAL DYNAMIC Addr[NumRecs] AS MyRecord

Addr[0].GivenName$ = "Katrina"
Addr[0].Surname$   = "Van Tassel"
Addr[0].Age%       = 16
Addr[0].Address$   = "18 North Broadway"
Addr[0].City$      = "Sleepy Hollow"
Addr[0].State$     = "N.Y."
Addr[0].Zip$       = "10591-1806"
Addr[0].Income#    = 1500250.98

Addr[1].GivenName$ = "Ichabod"
Addr[1].Surname$   = "Crane"
Addr[1].Age%       = 48
Addr[1].Address$   = "Route 9H"
Addr[1].City$      = "Kinderhook"
Addr[1].State$     = "NY"
Addr[1].Zip$       = "12106"
Addr[1].Income#    = 40.96
                   
Addr[2].GivenName$ = "Abraham 'Brom Bones'"
Addr[2].Surname$   = "Van Brunt"
Addr[2].Age%       = 19
Addr[2].Address$   = "540 North Broadway"
Addr[2].City$      = "North Tarrytown"
Addr[2].State$     = "New York"
Addr[2].Zip$       = "10591"
Addr[2].Income#    = 50025.98

CALL SortAndPrint(0)
CALL SortAndPrint(1)
CALL SortAndPrint(2)
CALL SortAndPrint(3)
CALL SortAndPrint(4)
CALL SortAndPrint(5)
CALL SortAndPrint(6)
CALL SortAndPrint(7)

SUB SortAndPrint (field)

  SELECT CASE field
    CASE 0
    QSORTIDX 0, 3, Addr.GivenName, 0
    CASE 1
    QSORTIDX 0, 3, Addr.Surname, 0
    CASE 2
    QSORTIDX 0, 3, Addr.Age, 1
    CASE 3
    QSORTIDX 0, 3, Addr.Address, 0
    CASE 4
    QSORTIDX 0, 3, Addr.City, 0
    CASE 5
    QSORTIDX 0, 3, Addr.State, 0
    CASE 6
    QSORTIDX 0, 3, Addr.Zip, 0
    CASE 7
    QSORTIDX 0, 3, Addr.Income, 2
  END SELECT

  FOR INTEGER i% = 0 TO LastRec
    PRINT "Record ", i%, " sorted by key ", RecData$[field]
    PRINT "GivenName: ", Addr[i].GivenName$
    PRINT "  Surname: ", Addr[i].Surname$
    PRINT "      Age: ", Addr[i].Age%
    PRINT "  Address: ", Addr[i].Address$
    PRINT "     City: ", Addr[i].City$
    PRINT "    State: ", Addr[i].State$
    PRINT " Zip Code: ", Addr[i].Zip$
    PRINT "   Income: ", Addr[i].Income#
    PRINT " "
  NEXT i%

END SUB

Example 4:

QSORTIDX 0, 10, &UDT[5].MemberToSort, 0