Worth to know for sorting in WinBatch.
;==========================================================================================================================================
; Worth to know for sorting in WinBatch.
;
; This is an attempt to understand what is going on with the data
; while using WinBatch native sorting functions (ItemSort, BinarySort)
; in comparison to user coded sorting algorithms working with WinBatch arrays.
;
; Detlev Dalitz.20090519.
;==========================================================================================================================================

GoSub DEFINE_FUNCTIONS

;--------------------------------------------------------------------------------------------------
; Define a string list with alpha, numerical and special characters.

strDelimiter = ","
strItemList = "A,B,C,c,\z,6.67E-11,-196,0,0.07,+0.07,1,+,-," ; 14 items.
intElements = ItemCount (strItemList, strDelimiter)

;--------------------------------------------------------------------------------------------------
; Define three arrays.

arrA = Arrayize (strItemList, strDelimiter) ; 'Automatic' array set from stringlist.

arrB = ArrDimension (intElements) ; Each element set manually.
arrB [0] = "A"          ; 2 = VT_STRING
arrB [1] = "B"          ; 2 = VT_STRING
arrB [2] = "C"          ; 2 = VT_STRING
arrB [3] = "c"          ; 2 = VT_STRING
arrB [4] = "\z"         ; 2 = VT_STRING
arrB [5] = "6.67E-11"   ; 2 = VT_STRING
arrB [6] = "-196"       ; 2 = VT_STRING
arrB [7] = "0"          ; 2 = VT_STRING
arrB [8] = "0.07"       ; 2 = VT_STRING
arrB [9] = "+0.07"      ; 2 = VT_STRING
arrB [10] = "1"         ; 2 = VT_STRING
arrB [11] = "+"         ; 2 = VT_STRING
arrB [12] = "-"         ; 2 = VT_STRING
arrB [13] = ""          ; 2 = VT_STRING

arrC = ArrDimension (intElements) ; Each element set manually.
arrC [0] = "A"          ; 2 = VT_STRING
arrC [1] = "B"          ; 2 = VT_STRING
arrC [2] = "C"          ; 2 = VT_STRING
arrC [3] = "c"          ; 2 = VT_STRING
arrC [4] = "\z"         ; 2 = VT_STRING
arrC [5] = 6.67E-11     ;32 = VT_FLOATNUM
arrC [6] = -196         ; 1 = VT_INTEGER
arrC [7] = 0            ; 1 = VT_INTEGER
arrC [8] = 0.07         ;32 = VT_FLOATNUM
arrC [9] = "+0.07"      ; 2 = VT_STRING
arrC [10] = 1           ; 1 = VT_INTEGER
arrC [11] = "+"         ; 2 = VT_STRING
arrC [12] = "-"         ; 2 = VT_STRING
arrC [13] = ""          ; 2 = VT_STRING


;--------------------------------------------------------------------------------------------------
; Note: The GnomeSort sorting algorithm is slow and only used here to keep the example simple.
;--------------------------------------------------------------------------------------------------
; Array sorting with 'ordinal' comparer function 'ChrStringToHex'.

intSortMode = 0 ; Sorting uses 'ordinal' comparer.
arrA = udfArrayGnomeSort (arrA, intSortMode)
strList0A = udfArrayItemize (arrA, strDelimiter)     ; ",+,+0.07,-,-196,0,0.07,1,6.67E-11,A,B,C,\z,c"
strList0AVT = udfArrayGetListVT (arrA, strDelimiter)   ; "2,2,2,2,2,2,2,2,2,2,2,2,2,2"

arrB = udfArrayGnomeSort (arrB, intSortMode)
strList0B = udfArrayItemize (arrB, strDelimiter)     ; ",+,+0.07,-,-196,0,0.07,1,6.67E-11,A,B,C,\z,c"
strList0BVT = udfArrayGetListVT (arrB, strDelimiter)   ; "2,2,2,2,2,2,2,2,2,2,2,2,2,2"

arrC = udfArrayGnomeSort (arrC, intSortMode)
strList0C = udfArrayItemize (arrC, strDelimiter)     ; ",+,+0.07,-,-196,0,0.07,1,6.67000000e-011,A,B,C,\z,c"
strList0CVT = udfArrayGetListVT (arrC, strDelimiter)   ; "2,2,2,2,1,1,32,1,32,2,2,2,2,2"


;--------------------------------------------------------------------------------------------------
; Array sorting with 'math symbol' comparer.

intSortMode = 1 ; Sorting uses 'math' comparer.
arrA = udfArrayGnomeSort (arrA, intSortMode)
strList1A = udfArrayItemize (arrA, strDelimiter)     ; ",-,\z,+,-196,0,6.67E-11,+0.07,0.07,1,A,B,c,C"
strList1AVT = udfArrayGetListVT (arrA, strDelimiter)   ; "2,2,2,2,2,2,2,2,2,2,2,2,2,2"

arrB = udfArrayGnomeSort (arrB, intSortMode)
strList1B = udfArrayItemize (arrB, strDelimiter)     ; ",-,\z,+,-196,0,6.67E-11,+0.07,0.07,1,A,B,c,C"
strList1BVT = udfArrayGetListVT (arrB, strDelimiter)   ; "2,2,2,2,2,2,2,2,2,2,2,2,2,2"

arrC = udfArrayGnomeSort (arrC, intSortMode)
strList1C = udfArrayItemize (arrC, strDelimiter)     ; ",-,\z,+,-196,0,6.67000000e-011,+0.07,0.07,1,A,B,c,C"
strList1CVT = udfArrayGetListVT (arrC, strDelimiter)   ; "2,2,2,2,1,1,32,2,32,1,2,2,2,2"


;--------------------------------------------------------------------------------------------------
; Array sorting with 'word' comparer function 'StrCmp'.

intSortMode = 2 ; Sorting uses 'word' comparer.
arrA = udfArrayGnomeSort (arrA, intSortMode)
strList2A = udfArrayItemize (arrA, strDelimiter)     ; ",-,\z,+,+0.07,0,0.07,1,-196,6.67E-11,A,B,c,C"
strList2AVT = udfArrayGetListVT (arrA, strDelimiter)   ; "2,2,2,2,2,2,2,2,2,2,2,2,2,2"

arrB = udfArrayGnomeSort (arrB, intSortMode)
strList2B = udfArrayItemize (arrB, strDelimiter)     ; ",-,\z,+,+0.07,0,0.07,1,-196,6.67E-11,A,B,c,C"
strList2BVT = udfArrayGetListVT (arrB, strDelimiter)   ; "2,2,2,2,2,2,2,2,2,2,2,2,2,2"

arrC = udfArrayGnomeSort (arrC, intSortMode)
strList2C = udfArrayItemize (arrC, strDelimiter)     ; ",-,\z,+,+0.07,0,0.07,1,-196,6.67000000e-011,A,B,c,C"
strList2CVT = udfArrayGetListVT (arrC, strDelimiter)   ; "2,2,2,2,2,1,32,1,1,32,2,2,2,2"


;--------------------------------------------------------------------------------------------------
; Stringlist sorting.

strListD = ItemSort (strItemList, strDelimiter)      ; ",-,\z,+,+0.07,0,0.07,1,-196,6.67E-11,A,B,c,C"
; Note: WinBatch function BinarySort with default sort key @STRING works alike.


;--------------------------------------------------------------------------------------------------
; Summary
;
;   1.
;   WinBatch native functions 'ItemSort' and 'BinarySort' internally use a 'word' sort algorithm
;   (see example output: strListD).
;
;   2.
;   If someone wants sorting an array and needs compatible result to 'ItemSort' and 'BinarySort',
;   then the sorting comparer must be a 'word sort' compatible function
;   like the WB native function 'StrCmp' does support.
;
;   3.
;   'Math sorting' (<,<=,==,>=,>) gives other result than using 'word sorting' (StrCmp).
;   'Word sorting' (StrCmp) gives other result than using 'Ordinal sorting' (ChrStringToHex).
;   'Ordinal sorting' (ChrStringToHex) gives other result than using 'Math sorting' .
;
;   4.
;   Each sorting comparer mode has its own behaviour when sorting various datatypes at once.
;
;   5.
;   On 'word sorting' a group of numerical chars with leading minus symbol '-'
;   (a negative numberstring resp. a negative integer) is treated as a string with leading hyphen.
;
;   6.
;   On 'math sorting' an array element with VarType VT_STRING which contains a string that can be
;   evaluated to a number (integer, floatnum) is treated during the comparison as having a
;   numerical datatype VT_INTEGER resp. VT_FLOATNUM.
;--------------------------------------------------------------------------------------------------
Exit
;==========================================================================================================================================



;==========================================================================================================================================
:DEFINE_FUNCTIONS
;==========================================================================================================================================
;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayGnomeSort (arrArray, intSortMode)
If !ArrInfo (arrArray, -1) Then Return ArrDimension (0) ; Invalid input array, return empty valid dim-0 array.
If ArrInfo (arrArray, 0) != 1 Then Return ArrDimension (0) ; Only dim-1 array allowed, return empty valid dim-0 array.
intElements = ArrInfo (arrArray, 1)
If intElements == 0 Then Return ArrDimension (0) ; Input array has no elements, return empty valid dim-0 array.
If intElements == 1 Then Return arrArray ; Input array has only one element, return the input array.
Switch intSortMode
Case 0
   intI = 1
   While intI < intElements
      If ChrStringToHex (arrArray [intI - 1]) <= ChrStringToHex (arrArray [intI])
         intI = intI + 1
      Else
         ArraySwapElements (arrArray, intI - 1, 0, 0, 0, 0, intI, 0, 0, 0, 0)
         intI = Max (1, intI - 1)
      EndIf
   EndWhile
   Break
Case 1
   intI = 1
   While intI < intElements
      If arrArray [intI - 1] <= arrArray [intI]
         intI = intI + 1
      Else
         ArraySwapElements (arrArray, intI - 1, 0, 0, 0, 0, intI, 0, 0, 0, 0)
         intI = Max (1, intI - 1)
      EndIf
   EndWhile
   Break
Case 2
   intI = 1
   While intI < intElements
      If StrCmp (arrArray [intI - 1], arrArray [intI]) < 1
         intI = intI + 1
      Else
         ArraySwapElements (arrArray, intI - 1, 0, 0, 0, 0, intI, 0, 0, 0, 0)
         intI = Max (1, intI - 1)
      EndIf
   EndWhile
   Break
EndSwitch
Return arrArray
;..........................................................................................................................................
; Gnome Sort - The Simplest Sort Algorithm
; The simplest sort algorithm is not Bubble Sort..., it is not Insertion Sort..., it's Gnome Sort!
; Gnome Sort is based on the technique used by the standard Dutch Garden Gnome (Du.: tuinkabouter).
; Here is how a garden gnome sorts a line of flower pots.
; Basically, he looks at the flower pot next to him and the previous one;
; if they are in the right order he steps one pot forward, otherwise he swaps them and steps one pot backwards.
; Boundary conditions: if there is no previous pot, he steps forwards; if there is no pot next to him, he is done.
; Dick Grune / dick@cs.vu.nl / http://www.cs.vu.nl/~dick/gnomesort.html
;
; IntSortMode = 0 ... 'Ordinal' sort using 'ChrStringToHex'.
; IntSortMode = 1 ... 'Math' sort using '<='.
; IntSortMode = 2 ... 'Word' sort using 'StrCmp'.
;
; Ported and tuned to WinBatch by Detlev Dalitz.20090518.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;----------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayItemize (arrArray, strDelimiter)
If !ArrInfo (arrArray, -1) Then Return "" ; No array.
If !ArrInfo (arrArray, 6) Then Return "" ; No elements.
If ArrInfo (arrArray, 0) > 1 Then Return "" ; Too much dimensions.
strItemList = ""
intHigh = Max (ArrInfo (arrArray, 1) - 1, 0)
intLow = 0
For intElem = intLow To intHigh
   If !!VarType (arrArray [intElem])
      strItemList = strItemList : strDelimiter : arrArray [intElem]
   Else
      strItemList = strItemList : strDelimiter
   EndIf
Next
Return StrSub (strItemList, 2, -1)
;----------------------------------------------------------------------------------------------------------------------
; This UDF "udfArrayItemize" converts a given dim-1 array into an itemlist
; with each item separated by delimiter character.
;
; Example: strMyItemList = udfArrayItemize (arrMyArray, @TAB)
; Creates an itemList from array.
;
; Note:
; This UDF supports only dim-1 array.
; An array element which is not initialized has a Vartype=0 (undefined).
; Therefore an empty item will be appended to target itemlist.
;
; Detlev Dalitz.20020718.20090508.20090516.
;----------------------------------------------------------------------------------------------------------------------
#EndFunction
;----------------------------------------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayGetListVT (arrArray, strDelimiter)
If !ArrInfo (arrArray, -1) Then Return "" ; Invalid input array, return empty string.
If ArrInfo (arrArray, 0) != 1 Then Return "" ; Only dim-1 array allowed, return empty string.
intElements = ArrInfo (arrArray, 1)
If intElements == 0 Then Return "" ; Input array has no elements, return empty string.
intHigh = intElements - 1
intLow = 0
strListVT = ""
For intI = intLow To intHigh
   strListVT = ItemInsert (VarType (arrArray [intI]), -1, strListVT, strDelimiter)
Next
Return strListVT
;..........................................................................................................................................
; Detlev Dalitz.20090516.
;..........................................................................................................................................
#EndFunction
;----------------------------------------------------------------------------------------------------------------------
;==========================================================================================================================================
Return ; from DEFINE_FUNCTIONS
;==========================================================================================================================================