Tfzmatrix

A collection of routines to simplify working with matrix structures written for TF version 5.0 beta 8
version 0.001d March 06, 2010
Added MatrixSortQS and MatrixSortQSP for large Matrix. After MUCH testing, timimg, tweaking, and debugging of the sort routines, I have opted to go with MatrixSortSS and MatrixSortQS(P) for all sorting. God help us all…

This rework of array.tf (by Nokie Quickfingers (moc.kemillib|ffej#moc.kemillib|ffej) (01/23/2002))
was undertaken because while the original _almost_ worked with vector arrays, it
would not handle maxrix structures. There were a few bug in it also.

Code was reworked to handle 'named' elements of a matrix. See examples below.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                                ZMATRIX.TF                               ;;;
;;;                                Zorbo on 3k                              ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; A collection of routines to simplify working with matrix structures
; written for TF version 5.0 beta 8
; 
; This rework of array.tf (by Nokie Quickfingers (jeff@billimek.com) (01/23/2002))
; was undertaken because while the original _almost_ worked with vector arrays, it 
; would not handle maxrix structures. There were a few bug in it also.
;
; Code was reworked to handle 'named' elements of a matrix. See examples below.
;
; version 0.001        March 03, 2010    Original version 
;
; version 0.001a    March 04, 2010    Tightened code and fixed bug in initializations. 
;
; version 0.001b    March 05, 2010    Added MatrixAdd and MatrixSortSS and tightened code. 
;
; version 0.001c    March 06, 2010    Added MatrixSortIS and WROTE IN STONE that MatrixStart will 
;                    point to the first index and not be 0 all the damn time. It will, 
;                    in fact, be 1 after the first MatrixPut and 0 for an empty matrix. 
;
; version 0.001d    March 06, 2010    Added MatrixSortQS and MatrixSortQSP for large Matrix. After MUCH testing,
;                    timimg, tweaking, and debugging of the sort routines, I have opted
;                    to go with MatrixSortSS and MatrixSortQS(P) for all sorting.
;                    God help us all...
;
; Macros included in this file are (* denotes STRUCTURE REQUIRED):
;
; MatrixAdd            *add to the matrix for it's structure. This is for Non Unique Key elements.
; MatrixAShow            *displays all elements in a matrix
; MatrixClear            clears out a matrix
; MatrixComp            compares named elements in the matrix with argument
; MatrixCountElements        *returns the count of the elements in the passed string (space delimited)
; MatrixDelete            *does a delete on the given index of the matrix, colapasing the data down
; MatrixElement            *returns either the number of elements or the requested element name
; MatrixForEach            loops through the matrix and does whatever you pass for the named element
; MatrixGet            returns an value for an element
; MatrixGetElement        *returns the nth numbered elelement of the passed string (space delimited)
; MatrixLen            returns the length of a matrix
; MatrixPurge            used internaly to clear array
; MatrixPut            inserts into matrix for index and element a value
; MatrixShow            displays all info for a matrix
; MatrixSort            *Main sorting routine, will size the matrix and choose the appropiate algorithims
; MatrixSortQS(P)        *Sorts matrix on field - used for large matrix - 1639 x 7 =~ 7.151 seconds for totaly random
; MatrixSortSS            *sorts matrix on field - used for small maxtrix - 62 x 9 =~ 0.02 seconds for totaly random
; MatrixStart            returns the first index in the matrix
; MatrixStructure        *returns or sets the 'structure' of the matrix
; MatrixUpdate            *does a replace or add to the matrix for it's structure based on A UNIQUE KEY ELEMENT
;
; As noted, several of these routines use the STRUCTURE construct. I implemented this for several reasons:
; 1) Allows this code to be VERY reuseable with no rewrites
; 2) Greatly simplfies the calling code
; 3) Changes to this code should NOT require changes to calling code, resulting in stable systems
; and last but not least
; 4) I saw it in a dream...
;
; normal initalization is to call MatrixClear(matrix_name) with the name of the matrix
; then call MatrixStructure(matrix_name,structure) with the name of the matrix and the structure
; 

/loaded z::zmatrix.tf

/require -q zmacros.tf

/set zmatrix_version=0.001d

;;; MatrixAdd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; *add to the matrix for it's structure. This is for Non Unique Key elements.
;
; syntax: MatrixAdd(<matrix_name>,<first_element>,<next_element>,...,<last element>)
; returns either -1 for error or index of added data
;
; example for a structure of: "class name area room xp name2 killdate"
;     /test MatrixUpdate("mobs",1365,"Priest","Darkmoore_[Drakacanus]","Church_(n_s)",1168," ","3/5/2010")
;
/def MatrixAdd = \
    /let matrix_name=%{1}%; \
    /shift%; \
    /if ({#} != MatrixElement(matrix_name)) \
        /echo -p -- $[zutoc({0},"BCyellow")] STRUCTURE ERROR: PASSED DATA DID NOT MATCH STRUCTURE.%; \
        /return -1%; \
    /endif%; \
    /let mindex=$[MatrixLen(matrix_name)]%; \
    /test ++mindex%; \
    /let cnt=0%; \
    /while ({#}) \
        /test ++cnt%; \
        /test MatrixPut(matrix_name,mindex,MatrixElement(matrix_name,cnt),{1})%; \
        /shift%; \
    /done%; \
    /return mindex

;;; MatrixAShow ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; *displays all elements in a matrix
;
; syntax: MatrixAShow(<matrix_name>)
; example: /test MatrixAShow("Components")
;
/def MatrixAShow = \
    /let matrix_name=%{1}%; \
    /let mcount=$[MatrixStart({matrix_name}) - 1]%;\
    /let nelements=$[MatrixStructure({matrix_name})]%; \
    /let res=%;\
    /while (++mcount<=MatrixLen({matrix_name})) \
            /let cnt=0%; \
            /while (++cnt<=MatrixElement({matrix_name})) \
            /let elementname=$[MatrixElement({matrix_name},cnt)]%; \
            /let res=$[MatrixGet({matrix_name},mcount,{elementname})] %res %;\
        /done%; \
    /done%;\
    /echo %res

;;; MatrixClear ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; clears out a matrix
;
; syntax: MatrixClear(<matrix_name>)
; example: /test MatrixClear("Components")
;
/def matrixclear = \
        /test MatrixPurge("MATRIX_%1__*")%;\
        /set MATRIX_%1__MAXLEN=0%;\
        /set MATRIX_%1__MINLEN=0

;;; MatrixComp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 
; used to FIND a index this compares named element in the matrix with argument
; returns the index of the matching element if found or 0 if not found
;
; syntax: MatrixComp(<matrix_name>,<element_name>,<argument to compare>)
; example: /let thisone=$[MatrixComp("Components","name","garnet")]
;
/def MatrixComp = \
    /let matrix_name=%{1}%; \
    /let element_name=%{2}%; \
    /let arg=%{3}%; \
    /let mforEachcount=$[MatrixStart(matrix_name) -1]%; \
    /let mforEachcount_max=$[MatrixLen(matrix_name)]%; \
    /let found_cmp=0%; \
    /let value=0%; \
    /while (++mforEachcount<=mforEachcount_max) \
        /test value:=strcmp(tolower({3}),tolower(MatrixGet({1},mforEachcount,{2})))%; \
        /if (value==0) \
            /let result=%{mforEachcount}%; \
            /break%; \
        /else \
            /let result=0%; \
        /endif%; \
    /done%; \
    /return {result}

;;; MatrixCountElements ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; *returns the count of the elements in the passed string (space delimited)
;
; syntax: /MatrixCountElements <structure_string>
; example: /let tempv=$(/MatrixCountElements $[MatrixStructure(matrix_name)])
;
/def MatrixCountElements = \
    /result {#}

;;; MatrixDelete ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; *does a delete on the given index of the matrix, colapasing the data down
;
; syntax: MatrixDelete(<matrix_name>,<index>)
; example: /test MatrixDelete("Components",MatrixComp("Components","name","garnet"))
;
/def MatrixDelete = \
    /let matrix_name=%{1}%; \
    /let mindex=%{2}%; \
    /if (mindex>MatrixLen(matrix_name)) \
        /echo -p -- $[zutoc({0},"BCyellow")] ERROR: Supplied Index out of range.%; \
        /return -1%; \
    /endif%; \
    /let mindex=$[mindex -1]%; \
    /let oneless=$[MatrixLen(matrix_name) -1]%; \
    /while (++mindex <= oneless) \
        /let next=$[mindex + 1]%; \
        /let cnt=0%; \
        /while (++cnt<=MatrixElement(matrix_name)) \
            /test MatrixPut(matrix_name,mindex,MatrixElement(matrix_name,cnt),MatrixGet(matrix_name,next,MatrixElement(matrix_name,cnt)))%; \
        /done%; \
    /done%; \
    /test MATRIX_%{matrix_name}__MAXLEN:=%{oneless}%; \
    /return 1

;;; MatrixElement ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 
; *returns either the number of elements or the requested element name
;
; syntax: MatrixElement(<matrix_name>[,<element_number>])
; example: /let numelements=$[MatrixElement("Components")]
; example: /let thiselement=$[MatrixElement("Components",1)]
;
/def MatrixElement = \
    /let matrix_name=%{1}%; \
    /if ({2}=~"") \
        /let metempv=$(/MatrixCountElements $[MatrixStructure(matrix_name)])%; \
        /return metempv%; \
    /else \
        /let metempv=$(/MatrixGetElement %{2} $[MatrixStructure(matrix_name)])%; \
        /return metempv%; \
    /endif

;;; MatrixForEach ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; loops through the matrix and does whatever you pass for the named element
;
; syntax: MatrixforEach(<matrix_name>,<element_name>,<command>)
; example: /test MatrixforEach("Components","name","/echo ")
;
/def MatrixforEach = \
        /let mforEachcount=$[MatrixStart({1}) - 1]%;\
        /let mforEachcount_max=$[MatrixLen({1})]%;\
        /while (++mforEachcount<=mforEachcount_max) \
           /eval -s0 %-2 $[MatrixGet({1},mforEachcount,{2})]%;\
        /done

;;; MatrixGet ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; returns an value for an element
;
; syntax: MatrixGet(<matrix_name>,<index>,"<element>")
; example: /set tempv=$[MatrixGet("Component",mindex,"total")]
;
/def MatrixGet = \
    /let value=%; \
        /test value:=\{MATRIX_%{1}___%{2}_%{3}\}%;\
        /return {value}

;;; *MatrixGetElement ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; returns the nth numbered elelement of the passed string (space delimited)
;
; syntax: /MatrixGetElement <n> <structure_string>
; example: /let tempv=$(/MatrixGetElement %{2} $[MatrixStructure(matrix_name)])%; \
;
/def MatrixGetElement = \
    /result {1} > 0 ? shift({1}), {1} : ""

;;; MatrixLen ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; returns the length of a matrix
;
; syntax: MatrixLen(<matrix_name>)
; example: /let num=$[MatrixLen("Components")]
;
/def MatrixLen = \
        /return \{MATRIX_%{1}__MAXLEN\}

;;; MatrixPurge ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; used internaly to clear array
;
; syntax: MatrixPurge(<mask>"
; example: /test purgematrix("MATRIX_%1__*")%;\
; 
/def MatrixPurge = \
        /let purge_vars=$(/listvar -s %{*})%;\
        /let off=$[strchr(purge_vars," ")]%;\
        /while (off>-1) \
           /unset $[substr(purge_vars,0,off)]%;\
           /let purge_vars=$[substr(purge_vars,off+1)]%;\
           /let off=$[strchr(purge_vars," ")]%;\
        /done%;\
        /unset %purge_vars%;

;;; MatrixPut ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; inserts into matrix for index and element a value
;
; syntax: MatrixPut(<matrix_name>,<index>,"<element>",value)
; example: /test MatrixPut("Component",foundit,"average",average)
;
/def MatrixPut = \
        /set MATRIX_%{1}___%{2}_%{3}=%{-3}%;\
        /if (MatrixStart({1})>{2}) /test MATRIX_%1__MINLEN:={2}%; /endif%;\
        /if (MatrixLen({1})<{2}) /test MATRIX_%1__MAXLEN:={2}%; /endif%; \
    /if (MatrixLen({1})==1) /test MATRIX_%1__MINLEN:=1%; /endif

;;; MatrixShow ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; displays all info for a matrix
;
; syntax: MatrixShow(<array_name>)
; example: /test MatrixShow("Components")
;
/def MatrixShow = \
        /listvar -g MATRIX_%{1}__*

;;; MatrixStart ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; returns the first index in the matrix
;
; syntax: MatrixStart(<array_name>)
; example: /let cnt=$[MatrixStart("Components")]
;
/def MatrixStart = \
        /return \{MATRIX_%{1}__MINLEN\}

;;; *MatrixStructure ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; returns or sets the 'structure' of the matrix
; if structure is set then the max_len is set to 0
; and the start is set to 0
; used to inform the matrix system of the structure of the matrix
;
; NOTE=UNIQUE KEY FIELD SHOULD BE FIRST IN LIST  if there is one
;
; syntax: MatrixStructure(<matrix_name>[,<structure>])
; example: /test MatrixStructure("components","name total legendary superior good average poor crude worthless")
; example: /let tempv=$[MatrixStructure("Components")
; 
/def MatrixStructure = \
    /let value=%; \
    /if ({#}==2) \
        /set MATRIX_%{1}__STRUCTURE=%{2}%; \
;        /set MATRIX_%{1}__MAXLEN=0%; \
;        /set MATRIX_%{1}__MINLEN=0%; \
        /return {2}%; \
    /elseif ({#}==1) \
        /test value:=\{MATRIX_%{1}__STRUCTURE\}%; \
        /return value%; \
    /endif%; \
    /echo -p -- $[zutoc({0},"BCyellow")] SYNTAX ERROR: 'MatrixStructure(<matrix_name>[,<structure>])'.

;;; *MatrixUpdate ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; does a replace or add to the matrix for it's structure based on A UNIQUE KEY ELEMENT
; The unique key element is FIRST in the STRUCTURE LIST
; IF the matrix does NOT require or have a unique key, then use MatrixAdd, MatrixPut,
; and MatrixDelete where you will be responsable for locating the proper index.
;
; Also note that when calling this routine you will need to supply data matching
; the ENTIRE STRUCTURE.
;  
; syntax: MatrixUpdate(<matrix_name>,<key_element>,<next_element>,...,<last element>)
; 
; example for a structure of: "name total legendary superior good average poor crude worthless"
;     /test MatrixUpdate("Components","garnet",2,1,1,0,0,0,0,0)
;
/def MatrixUpdate = \
    /let matrix_name=%{1}%; \
    /shift%; \
    /if ({#} != MatrixElement(matrix_name)) \
        /echo -p -- $[zutoc({0},"BCyellow")] STRUCTURE ERROR: PASSED DATA DID NOT MATCH STRUCTURE.%; \
        /return -1%; \
    /endif%; \
    /let mindex=$[MatrixComp(matrix_name,MatrixElement(matrix_name,1),{1})]%; \
    /if (mindex<1) \
        /let mindex=$[MatrixLen(matrix_name)]%; \
        /test ++mindex%; \
    /endif%; \
    /let cnt=0%; \
    /while ({#}) \
        /test ++cnt%; \
        /test MatrixPut(matrix_name,mindex,MatrixElement(matrix_name,cnt),{1})%; \
        /shift%; \
    /done%; \
    /return mindex

;;; MatrixSort ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Call this instead of the individual sorting routines
;
; Syntax: MatrixSort(<matrixname>,<element_name>,"<a|d>","<c|i|n>")
;    <matrix_name>    the name of the matrix
;    <element_name>    name of the element to sort on
;    <a|d>        ascending or decending
;    <c|i|n>        comparisons are 'c'ase sensitive or 'i'gnore case or 'n'umeric 
;
; example: /test MatrixSort("components","name","a","i")
; example: /test MatrixSort("components","total","d","n")
;
/def MatrixSort = \
    /let mmin=0%; \
    /let mmax=0%; \
    /let msize=0%; \
    /let tsize=0%; \
    /test mmin:=MatrixStart({1})%; \
    /test mmax:=MatrixLen({1})%; \
    /test msize:={mmax} - {mmin}%; \
    /test tsize:={msize} * MatrixElement({1})%; \
;    /echo -p -- $[zutoc({0},"BCyellow")] Size of matrix to sort: %{msize} x $[MatrixElement({1})] or %{tsize}%; \
    /if (tsize<=100) \
;        /echo -p -- $[zutoc({0},"BCyellow")] Using MatrixSortSS with %{mmin} %{mmax}%; \
        /test MatrixSortSS({1},{2},mmin,mmax,{3},{4})%; \
;        /return {?}%; \
    /else \
;        /echo -p -- $[zutoc({0},"BCyellow")] Using MatrixSortQS%; \
        /test MatrixSortQS({1},{2},mmin,mmax,{3},{4})%; \
    /endif

;;; *MatrixSortSS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; sorts matrix on given field
; uses STRUCTURE
;
; This is a Selection Sort routine and is moderatly quick for lengths up to ~100
; included for a quick and dirty (brute force) sort. Very little memory footprint.
; 
; timiming notes:    Matrix size    time
;            60 x 9        ~0.012 seconds
;            1600 x 7    ~33 seconds
;
; syntax: MatrixSortSS(<matrixname>,<element_name>,<start_index>,<end_index>,"<a|d>","<c|i|n>")
;    <matrix_name>    the name of the matrix
;    <element_name>    name of the element to sort on
;    <start_index>    start of sort
;    <end_index>    end of sort
;    <a|d>        ascending or decending
;    <c|i|n>        comparisons are 'c'ase sensitive or 'i'gnore case or 'n'umeric 
;
; example: /test MatrixSortSS("components","name",start,end,"a","i")
; example: /test MatrixSortSS("components","total",start,end,"d","n")
;
/def MatrixSortSS = \
    /let matrix_name=%{1}%; \
    /let element_name=%{2}%; \
    /let lMin=%{3}%; \
    /let lMax=%{4}%; \
    /let sort_type=%{5}%; \
    /let alpha_numeric=%{6}%; \
        /let sSmallest=%; \
    /let lSmallest=%; \
    /let lCount1=0%; \
    /let lCount2=0%; \
    /let lMaxOneLess=0%; \
    /let tempv=0%; \
    /if (lMin==lMax) \
        /return 1%; \
    /endif%; \
    /test lMaxOneLess:={lMax} - 1%; \
    /test lCount1:={lMin} - 1%; \
    /while (++lCount1<=lMaxOneLess) \
        /test sSmallest:=MatrixGet(matrix_name,lCount1,element_name)%; \
        /test lSmallest:={lCount1}%; \
        /test lCount2:={lCount1}-1%; \
        /while (++lCount2<=lMax) \
            /let tempv=$[MatrixGet(matrix_name,lCount2,element_name)]%; \
            /let check=0%; \
            /if (alpha_numeric=~"n") \
                /test check:={tempv} - {sSmallest}%; \
            /elseif (alpha_numeric=~"i") \
                /test check:=strcmp(tolower(tempv),tolower(sSmallest))%; \
            /else \
                /test check:=strcmp(tempv,sSmallest)%; \
            /endif%; \
            /if (sort_type=~"a" & check<0) \
                /test sSmallest:=MatrixGet(matrix_name,lCount2,element_name)%; \
                /test lSmallest:={lCount2}%; \
            /elseif (sort_type=~"d" & check>0) \
                /test sSmallest:=MatrixGet(matrix_name,lCount2,element_name)%; \
                /test lSmallest:={lCount2}%; \
            /endif%; \
        /done%; \
        /If (lSmallest!=lCount1) \
            /let cnt=0%; \
            /let numele=$[MatrixElement(matrix_name)]%; \
            /while (++cnt<=numele) \
                /let tempsmallest_%{cnt}=$[MatrixGet(matrix_name,lSmallest,MatrixElement(matrix_name,cnt))]%; \
            /done%; \
            /let cnt=0%; \
            /while (++cnt<=numele) \
                /let nameele=$[MatrixElement(matrix_name,cnt)]%; \
;                /let value=$[MatrixGet(matrix_name,lCount1,MatrixElement(matrix_name,cnt))]%; \
                /test MatrixPut(matrix_name,lSmallest,nameele,MatrixGet(matrix_name,lCount1,nameele))%; \
            /done%; \
            /let cnt=0%; \
            /let value=%; \
            /while (++cnt<=numele) \
                    /test value:=\{tempsmallest_%{cnt}\}%;\
                /test MatrixPut(matrix_name,lCount1,MatrixElement(matrix_name,cnt),value)%; \
            /done%; \
        /endif%; \
        /done%; \
    /Zpurgevars tempsmallest_*

;;; MatrixSortQS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; syntax: MatrixSortQS(<matrix_name>,<element_name>,<StartSortingRegion>,<EndSortingRegion>,<a|d>,<c|i|n>
;
; <matrix_name>        Matrix to sort
; <element_name>    Name of element to sort on
; <StartSortingRegion>    Start of sortin region within matrix
; <EndSortingRegion>    End of sortin region within matrix
; <a|d>            'a'scending or 'd'escending
; <c|i|n>        'c'ase sensitive, 'i'gnore case, or 'n'umeric
; 
; examples: /test MatrixSortQS("mobs","class",MatrixStart("mobs"),MatrixLen("mobs"),"a","n"
;
; This version of quicksort is faster than MatrixSortSS for larger arrays. 
; It delegates to MatrixSortSS for small arrays and when partition is small
;
/def MatrixSortQS = \
    /let matrix_name=%{1}%; \
    /let element_name=%{2}%; \
    /let lLowerPoint=%{3}%; \
    /let lUpperPoint=%{4}%; \
    /let sort_type=%{5}%; \
    /let alpha_numeric=%{6}%; \
    /let delegate=60%; \
    /let lMidPoint=0%; \
    /let tempv=0%; \
    /if ((lUpperPoint - lLowerPoint) <= delegate) \
        /test MatrixSortSS(matrix_name,element_name,lLowerPoint,lUpperPoint,sort_type,alpha_numeric)%; \
        /break%; \
    /endif%; \
;    Do the quick sort
    /While (lLowerPoint < lUpperPoint) \
;        Find a mid point (split the array into partitions)
        /test lMidPoint:=MatrixSortQSP(matrix_name,element_name,lLowerPoint,lUpperPoint,sort_type,alpha_numeric)%; \
;        Recurively sort the smaller partition
        /if ((lMidPoint - lLowerPoint) <= (lUpperPoint - lMidPoint)) \
            /test tempv:={lMidPoint} - 1%; \
            /test MatrixSortQS(matrix_name,element_name,lLowerPoint,tempv,sort_type,alpha_numeric)%; \
            /test lLowerPoint:={lMidPoint} + 1%; \
        /else \
            /test ltempv:={lMidPoint} + 1%; \
            /test MatrixSortQS(matrix_name,element_name,ltempv,lUpperPoint,sort_type,alpha_numeric)%; \
            /test lUpperPoint:={lMidPoint} - 1%; \
        /endif%; \
    /Done

;;; MatrixSortQSP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; example: MatrixSortQSP(matrix_name,element_name,lLowerPoint,lUpperPoint,sort_type,alpha_numeric)
;
; Selects a pivot point and moves smaller entries to one side of it and larger
; entries to the other side of it.  Returns the position of the pivot point
; when finished.
;
/def MatrixSortQSP = \
    /let matrix_name=%{1}%; \
    /let element_name=%{2}%; \
    /let lLow=%{3}%; \
    /let lHigh=%{4}%; \
    /let sort_type=%{5}%; \
    /let alpha_numeric=%{6}%; \
    /let lPivot=0%; \
    /let sPivot=%; \
    /let lLowCount=0%; \
    /let lHighCount=0%; \
    /let sTemp=%; \
    /let tempv=0%; \
    /let tempvalue= %; \
;    Select pivot point and exchange with first element
    /test lPivot:=({lLow} + ({lHigh} - {lLow}) / 2)%; \
    /test sPivot:=MatrixGet(matrix_name,lPivot,element_name)%; \
    /let cnt=0%; \
    /let numele=$[MatrixElement(matrix_name)]%; \
    /while (++cnt<=numele) \
        /let tempsPivot_%{cnt}=$[MatrixGet(matrix_name,lPivot,MatrixElement(matrix_name,cnt))]%; \
    /done%; \
    /let cnt=0%; \
    /while (++cnt<=numele) \
        /let nameele=$[MatrixElement(matrix_name,cnt)]%; \
        /test MatrixPut(matrix_name,lPivot,nameele,MatrixGet(matrix_name,lLow,nameele))%; \
    /done%; \
    /test lLowCount:={lLow} + 1%; \
    /test lHighCount:={lHigh}%; \
;    Continually loop moving entries smaller than pivot to one side and larger than pivot to other side
    /while (1) \
        /while (lLowCount < lHighCount) \
            /let tempv=$[MatrixGet(matrix_name,lLowCount,element_name)]%; \
            /let check=0%; \
            /if (alpha_numeric=~"n") \
                /test check:=sPivot - tempv%; \
            /elseif (alpha_numeric=~"i") \
                /test check:=strcmp(tolower(sPivot),tolower(tempv))%; \
            /else \
                /test check:=strcmp(sPivot,tempv)%; \
            /endif%; \
            /if (sort_type=~"a") \
                /if (check<0) \
                    /break%; \
                /else \
                    /test lLowCount:={lLowCount} + 1%; \
                /endif%; \
            /elseif (sort_type=~"d") \
                /if (check>0) \
                    /break%; \
                /else \
                    /test lLowCount:={lLowCount} + 1%; \
                /endif%; \
            /endif%; \
        /done%; \
        /while (lHighCount >= lLowCount) \
            /let tempv=$[MatrixGet(matrix_name,lHighCount,element_name)]%; \
            /let check=0%; \
            /if (alpha_numeric=~"n") \
                /test check:=tempv - sPivot%; \
            /elseif (alpha_numeric=~"i") \
                /test check:=strcmp(tolower(tempv),tolower(sPivot))%; \
            /else \
                /test check:=strcmp(tempv,sPivot)%; \
            /endif%; \
            /if (sort_type=~"a") \
                /If (check<0) \
                    /break%; \
                /else \
                    /test lHighCount:={lHighCount} - 1%; \
                /endif%; \
            /elseif (sort_type=~"d") \
                /If (check>0) \
                    /break%;\
                /else \
                    /test lHighCount:={lHighCount} - 1%; \
                /endif%; \
            /endif%; \
        /done%; \
        /if (lLowCount >= lHighCount) \
            /break 1%; \
        /endif%; \
;        Swap the items
        /let cnt=0%; \
        /while (++cnt<=numele) \
            /let tempsTemp_%{cnt}=$[MatrixGet(matrix_name,lLowCount,MatrixElement(matrix_name,cnt))]%; \
        /done%; \
        /let cnt=0%; \
        /while (++cnt<=numele) \
            /let nameele=$[MatrixElement(matrix_name,cnt)]%; \
            /test MatrixPut(matrix_name,lLowCount,nameele,MatrixGet(matrix_name,lHighCount,nameele))%; \
        /done%; \
        /let cnt=0%; \
        /while (++cnt<=numele) \
            /test tempvalue:=\{tempsTemp_%{cnt}\}%;\
            /test MatrixPut(matrix_name,lHighCount,MatrixElement(matrix_name,cnt),tempvalue)%; \
        /done%; \
        /test lHighCount:={lHighCount} - 1%; \
        /test lLowCount:={lLowCount} + 1%; \
    /done%; \
    /let cnt=0%; \
    /while (++cnt<=numele) \
        /let nameele=$[MatrixElement(matrix_name,cnt)]%; \
        /test MatrixPut(matrix_name,lLow,nameele,MatrixGet(matrix_name,lHighCount,nameele))%; \
    /done%; \
    /let cnt=0%; \
    /while (++cnt<=numele) \
        /test tempvalue:=\{tempsPivot_%{cnt}\}%;\
        /test MatrixPut(matrix_name,lHighCount,MatrixElement(matrix_name,cnt),tempvalue)%; \
    /done%; \
    /return {lHighCount}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License