SORTA (Sort an Array)

Code Factor 1 Extended Factor 2
SORTA(A/D)   Array or keyed-ds-array
    %SUBARR(Array or keyed-ds-array : start-element {: number-of-elements} )
    SORTA{(A/D)} ds-array %FIELDS(subfield1 { : subfield2 { ... } })
    SORTA{(A/D)} %SUBARR(ds-array : start-element {: number-of-elements} ) %FIELDS(subfield1: { : subfield2 { ... } })

For a scalar array, the array-name operand is the name of an array to be sorted. The array *IN cannot be specified. If the array is defined as a compile-time or prerun-time array with data in alternating form, the alternate array is not sorted. Only the array specified as array-name is sorted.

For an array data structure, you can sort by one subfield using the keyed-ds-array syntax, or you can sort by more than one subfield using %FIELDS to specify the required subfields.
  • The keyed-ds-array operand is a qualified name consisting of the array to be sorted followed by the subfield to be used as a key for the sort. The array data structure to be sorted is indicated by specifying * as the index for the array. For example, if array data structure INFO has subfields NAME and SALARY, then to sort array INFO using subfield NAME as a key, specify INFO(*).NAME as the operand for SORTA. To sort the INFO array by SALARY, specify INFO(*).SALARY as the operand for SORTA.
  • To sort the array data structure by more than one subfield, list the required subfields using %FIELDS. For example, if array data structure INFO has subfields NAME and SALARY, then to sort array INFO by SALARY and NAME, specify INFO as the first operand for SORTA and specify %FIELDS(SALARY:NAME) as the second operand. When two array elements are compared, the SALARY subfields are compared first. If the SALARY subfields are equal, then the NAME subfield is compared next. If the NAME subfields are equal, then the array elements are considered to be equal.
    
    SORTA INFO %FIELDS(SALARY : NAME):
    

    For more information, see %FIELDS (Subfields for sorting).

If the sequence for the array is defined by the ASCEND or DESCEND keyword on the definition specification for the array, then the array is always sorted in that sequence. If no sequence is specified for the array, then the sequence defaults to ascending sequence. If the 'A' operation extender is specified, then the array is sorted in ascending sequence. If the 'D' operation extender is specified, then the array is sorted in descending sequence.

Note: The ASCEND and DESCEND keywords cannot be specified for an array data structure.

If the array is defined with the OVERLAY keyword and the 'A' or 'D' operation extender is not specified, the base array will be sorted in the sequence defined by the OVERLAY array.

Graphic and UCS-2 arrays will be sorted by the hexadecimal values of the array elements, disregarding the alternate collating sequence, in the order specified on the definition specification.

To sort a portion of an array, use the %SUBARR built-in function.

Note:
  1. Sorting an array does not preserve any previous order. For example, if you sort an array twice, using different overlay arrays, the final sequence will be that of the last sort. Elements that are equal in the sort sequence but have different hexadecimal values (for example, due to alternate collating sequence or the use of an overlay array to determine sequence), may not be in the same order after sorting as they were before.
  2. When sorting arrays of basing pointers, you must ensure that all values in the arrays are addresses within the same space. Otherwise, inconsistent results may occur. See Compare Operations for more information.
  3. If a null-capable array is sorted, the sorting will not take the settings of the null flags into consideration.
  4. Sorting a dynamically allocated array without all defined elements allocated may cause errors to occur. Use the %SUBARR built-in function to limit the sort to only the allocated elements.
  5. The 'A' operation extender is not allowed when sorting an array that is defined with the DESCEND keyword and the 'D' operation extender is not allowed when sorting an array that is defined with the ASCEND keyword.
  6. When sorting an array data structure using the keyed array data structure syntax DS(*).SUBFIELD:
    1. The part of the qualified name preceding the (*) index must represent an array, and the part of the qualified name after the (*) must represent a scalar subfield or an indexed scalar array.
    2. If there is more than one array subfield in a complex qualified name, only one array subfield can be sorted. All other arrays in the qualified name must have an index specified. For example, if array data structure FAMILY has an array subfield CHILD and the CHILD elements have an array subfield PET, and the PET subfield has a subfield NAME, then only one of the FAMILY, CHILD and PET arrays can be sorted in one SORTA operation. If the CHILD array is to be sorted, then the FAMILY and PET arrays must have explicit indexes. One valid operand for SORTA would be FAMILY(i).CHILD(*).PET(1).NAME. That SORTA operation would sort the CHILD array of FAMILY(i) by the NAME subfield of PET(1).
    3. An array data structure is sorted in the ascending sequence of the key unless the 'D' operation extender is specified.
    4. If the sort key is an element of a sequenced array, its sequence is not considered when sorting the array data structure.

For more information, see Array Operations.

Figure 1. SORTA Operation
*...1....+....2....+....3....+....4....+....5....+....6....+....7...+....
DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++
DARRY             S              1A   DIM(8) ASCEND
DARRY2            S              1A   DIM(8)
CL0N01Factor1+++++++Opcode(E)+Factor2+++++++Result++++++++Len++D+HiLoEq....
 *
 *  The SORTA operation sorts ARRY into ascending sequence because
 *  the ASCEND keyword is specified.
 *  If the unsorted ARRY contents were GT1BA2L0, the sorted ARRY
 *  contents would be ABGLT012.
C                   SORTA     ARRY

 *  The SORTA operation sorts ARRY2 into descending ascending sequence
 *  the (D) operation extender is specified.
 *  If the unsorted ARRY2 contents were GT1BA2L0, the sorted ARRY2
 *  contents would be 210TLGBA.
C                   SORTA(D)  ARRY2
Figure 2. SORTA Operation with OVERLAY
*...1....+....2....+....3....+....4....+....5....+....6....+....7...+....
DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++++
 * In this example, the base array has the values aa44 bb33 cc22 dd11
 * so the overlaid array ARRO has the values 44 33 22 11.
D                 DS
D ARR                            4    DIM(4) ASCEND
D ARRO                           2    OVERLAY(ARR:3)
D
CL0N01Factor1+++++++Opcode(E)+Factor2+++++++Result++++++++Len++D+HiLoEq....
C
 * After the SORTA operation, the base array has the values
 * dd11 cc22 bb33 aa44
C
C                   SORTA     ARRO
Figure 3. SORTA Operation Ascending or Descending
 * The names array does not have a sequence keyword
 * (ASCEND or DESCEND) specified.
D info            DS                  QUALIFIED
D   names                       10A   DIM(2)

 /free

    // Initialize the array
    info.names(1) = 'Bart';
    info.names(2) = 'Lisa';

    // Sort the info.names in descending order
    SORTA(D) info.names;
    // info.names(1) = 'Lisa'
    // info.names(2) = 'Bart'

    // Sort the info.names in ascending order
    SORTA(A) info.names;
    // info.names(1) = 'Bart'
    // info.names(2) = 'Lisa'

    // With no operation extender, it defaults to ascending order
    SORTA info.names;
    // info.names(1) = 'Bart'
    // info.names(2) = 'Lisa'
Figure 4. SORTA Operation with an Array Data Structure using the Keyed Array Data Structure Syntax
D emp             DS                  QUALIFIED DIM(25)
D   name                        25A   VARYING
D   salary                       9P 2
D numEmp          S             10I 0

// Initialize the data structure
emp(1).name = 'Maria';
emp(1).salary = 1100;
emp(2).name = 'Pablo';
emp(2).salary = 1200;
emp(3).name = 'Bill';
emp(3).salary = 1000;
emp(4).name = 'Alex';
emp(4).salary = 1300;
numEmp = 4;

// Sort the EMP array using the NAME subfield as a key
SORTA %subarr(emp(*).name : 1 : numEmp);
// emp(1).name = 'Alex'       <-----
// emp(1).salary = 1300
// emp(2).name = 'Bill'       <-----
// emp(2).salary = 1000
// emp(3).name = 'Maria'      <-----
// emp(3).salary = 1100
// emp(4).name = 'Pablo'      <-----
// emp(4).salary = 1200

// Sort the EMP array using the SALARY subfield as a key
SORTA %subarr(emp(*).salary : 1 : numEmp);
// emp(1).name = 'Bill'
// emp(1).salary = 1000       <-----
// emp(2).name = 'Maria'
// emp(2).salary = 1100       <-----
// emp(3).name = 'Pablo'
// emp(3).salary = 1200       <-----
// emp(4).name = 'Alex'
// emp(4).salary = 1300       <-----

// Sort the EMP array descending using the SALARY subfield
SORTA(D) %subarr(emp(*).salary : 1 : numEmp);
// emp(1).name = 'Alex'
// emp(1).salary = 1300       <-----
// emp(2).name = 'Pablo'
// emp(2).salary = 1200       <-----
// emp(3).name = 'Maria'
// emp(3).salary = 1100       <-----
// emp(4).name = 'Bill'
// emp(4).salary = 1000       <-----
Figure 5. SORTA Operation with an Array Data Structure using %FIELDS to sort by more than one subfield
D emp             DS                  QUALIFIED DIM(25)
D   name                        25A   VARYING
D   salary                       9P 2
D numEmp          S             10I 0

// Initialize the data structure
emp(1).name = 'Maria';
emp(1).salary = 1300;
emp(2).name = 'Pablo';
emp(2).salary = 1200;
emp(3).name = 'Bill';
emp(3).salary = 1100;
emp(4).name = 'Alex';
emp(4).salary = 1200;
numEmp = 4;

// Sort the EMP array using the SALARY and NAME subfields
SORTA %SUBARR(emp : 1 : numEmp) %FIELDS(salary : name);
// emp(1).name = 'Bill'
// emp(1).salary = 1100       <-----
// emp(2).name = 'Alex'       <-----
// emp(2).salary = 1200       <-----
// emp(3).name = 'Pablo'      <-----
// emp(3).salary = 1200       <-----
// emp(4).name = 'Maria'
// emp(4).salary = 1300       <-----
Figure 6. SORTA Operation with a Complex Array Data Structure
D emp_t           DS                  QUALIFIED TEMPLATE
D   name                        25A   VARYING
D teams           DS                  QUALIFIED DIM(2)
D   manager                     25A   VARYING
D   emps                              LIKEDS(emp_t) DIM(2)

// Initialize the data structure
teams(1).manager = 'Jack';
teams(1).emps(1).name = 'Yvonne';
teams(1).emps(2).name = 'Mary';
teams(2).manager = 'Ann';
teams(2).emps(1).name = 'Wendy';
teams(2).emps(2).name = 'Thomas';

// Sort the TEAMS array using the MANAGER subfield as a key
SORTA teams(*).manager;
//    teams(1).manager = 'Ann'           <-----
//    teams(1).emps(1).name = 'Wendy'
//    teams(1).emps(2).name = 'Thomas'
//    teams(2).manager = 'Jack'          <-----
//    teams(2).emps(1).name = 'Yvonne'
//    teams(2).emps(2).name = 'Mary'

// Sort the TEAMS array using the EMPS(2).NAME subfield as a key
SORTA teams(*).emps(2).name;
//    teams(1).manager = 'Jack'
//    teams(1).emps(1).name = 'Yvonne'
//    teams(1).emps(2).name = 'Mary'     <-----
//    teams(2).manager = 'Ann'
//    teams(2).emps(1).name = 'Wendy'
//    teams(2).emps(2).name = 'Thomas'   <-----

// Sort the TEAMS(1).EMPS array using the NAME subfield as a key
SORTA teams(1).emps(*).name;
//    teams(1).manager = 'Jack'
//    teams(1).emps(1).name = 'Mary'     <-----
//    teams(1).emps(2).name = 'Yvonne'   <-----
//    teams(2).manager = 'Ann'
//    teams(2).emps(1).name = 'Wendy'
//    teams(2).emps(2).name = 'Thomas'

// Sort the TEAMS array first by the MANAGER subfield
// and then by the EMPS.NAME subfields
SORTA teams(*).manager;
for i = 1 to %ELEM(TEAMS);
   SORTA teams(i).emps(*).name;
endfor;
// After the first sort, by MANAGER:
//    teams(1).manager = 'Ann'           <-----
//    teams(1).emps(1).name = 'Wendy'
//    teams(1).emps(2).name = 'Thomas'
//    teams(2).manager = 'Jack'          <-----
//    teams(2).emps(1).name = 'Mary'
//    teams(2).emps(2).name = 'Yvonne'
// After loop with the second sort, by EMPS.NAME:
//    teams(1).manager = 'Ann'
//    teams(1).emps(1).name = 'Thomas'   <----- 1
//    teams(1).emps(2).name = 'Wendy'    <----- 1
//    teams(2).manager = 'Jack'
//    teams(2).emps(1).name = 'Mary'     <----- 2
//    teams(2).emps(2).name = 'Yvonne'   <----- 2