Sorting an (dynamic) array

Dear fellow Natural developers :slight_smile:

What is the best (fastest) way to sort an (dynamic) array in Natural? I use code like the following:

DEFINE DATA
*
PARAMETER
01 #ARRAY (A/1:*) DYNAMIC
*
LOCAL
01 #NUMBER-OF-ELEMENTS (I4)
01 #ARRAY-TEMP (A/1:*) DYNAMIC
01 #ELEMENT (A1000) /* DYNAMIC is not allowed with SORT!
01 #A (I4)
01 #T (I4)
*
END-DEFINE
*
********************************************************************************
DEFINE SUBROUTINE SORT-ARRAY
********************************************************************************
*
#NUMBER-OF-ELEMENTS := *OCC(#ARRAY)
IF #NUMBER-OF-ELEMENTS EQ 0
  ESCAPE MODULE
END-IF
*
RESIZE ARRAY #ARRAY-TEMP TO (1:#NUMBER-OF-ELEMENTS)
#T := 0
*
FOR #A 1 #NUMBER-OF-ELEMENTS
  #ELEMENT := #ARRAY(#A)
END-ALL
*
SORT BY #ELEMENT USING KEY
  ADD 1 TO #T
  #ARRAY-TEMP(#T) := #ELEMENT
END-SORT
*
RESET #ARRAY(*)
#ARRAY(*) := #ARRAY-TEMP(*)
*
END-SUBROUTINE
********************************************************************************
*
END

This works but I don’t know if it really is the best possible way. Especially when sorting a multi-dimensional array I need a temp field for every original field in the array and this is very error prone:

FOR #C 1 ARRAY.NUMBER-OF-ELEMENTS
  #KEY-SORT := ARRAY.KEY
  #VAR1-SORT := ARRAY.VAR1(#C)
  #VAR2-SORT := ARRAY.VAR2(#C)
  ...
END-ALL
*
SORT BY #KEY-SORT USING
    #VAR1-SORT
    #VAR2-SORT
    ...
END-SORT

Is there a better way to sort an array?

Best regards,
Stefan

Hi Stefan,

You really do not need a temp array at all.

See the code below:

DEFINE DATA
local
01 #A (I4)
01 #T (I4)
1 #array (n2/1:10) init <2>
1 #temp (n2)
*
END-DEFINE
*
for #a = 1 to 10
move #array (#a) to #temp
end-all
sort by #temp using keys
add 1 to #t
move #temp to #array (#t)
end-sort
write #array (*)
end

If you run this you will see it work quite well.
Basically, internally, Natural creates an array which is your temp-array.
After the SORT, you are getting successive values back from the sort; that is, you are getting successive values of what you call temp-array.

For a multi dimensional array all you need is something like:

DEFINE DATA
local
01 #A (I4)
01 #B (i4)
01 #T (I4)
1 #array (n2/1:10,1:5) init <2>
1 redefine #array
2 #aaa (n2/1:50)
1 #temp (n2)
*
END-DEFINE
*
for #a = 1 to 10
for #b = 1 to 5
move #array (#a,#b) to #temp
end-all
sort by #temp using keys
add 1 to #t
move #temp to #aaa (#t)
end-sort
write #array (*)
end

I haven’t run the 2 dim example (did run the 1 dim), but it should work.

Also, the code above should be easily adaptable to DYNAMIC.

steve

Dear Steve,

thank you! That definitely reduces the amount of code needed for this simple task :slight_smile:

Best regards,
Stefan