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}