|
Sort AlgorithmsAs of version 5.07, Miva Script has a built the build in function miva_array_sort(). But there are faster sorts available and many other sort algorithms available that can be educational to study. These are provided below from the slowest to the fastest. The fastest specifically take advantage of built in capabilities of the Miva Script language. Included Sort Routines
Bubble SortThe Bubble sort, originally know as "sorting by exchange", is a simple sort that works by repeatedly stepping through the list to be sorted, comparing each pair of adjacent items and swapping them if they are in the wrong order. Multiple passes through the list are repeated until the list is sorted. The term "bubble sort" was coined in 1962, by K.E. Iverson. dreamincode.com It is simple to understand if not the fastest. The Miva Script implementation was coded by Ray Yates. Watch this video to see a Bubble sort in action. Relative speed: 530 elements per sec.Example: Suitable for sorting dozens of items.<MvFUNCTION NAME="Bubblesort" PARAMETERS="list" STANDARDOUTPUTLEVEL=""> <MvCOMMENT> Simple single dimension array bubblesort procedure bubbleSort( A : list of sortable items ) defined as: do swapped := false for each i in 0 to length( A ) - 1 do: if A[ i ] > A[ i + 1 ] then swap( A[ i ], A[ i + 1 ] ) swapped := true end if end for while swapped end procedure </MvCOMMENT> <MvASSIGN NAME="l.swapped" VALUE="{ 1 }"> <MvASSIGN NAME="l.maxlist" VALUE="{ miva_array_elements(l.list) -1 }"> <MvWHILE EXPR="{ l.swapped }"> <MvASSIGN NAME="l.swapped" VALUE="{ 0 }"> <MvASSIGN NAME="l.ndx" VALUE="{ 1 }"> <MvWHILE EXPR="{ l.ndx LE l.maxlist }"> <MvIF EXPR="{ l.list[l.ndx] GT l.list[l.ndx + 1] }"> <MvCOMMENT> swap </MvCOMMENT> <MvASSIGN NAME="l.temp" VALUE="{ l.list[l.ndx] }"> <MvASSIGN NAME="l.list" INDEX="{ l.ndx }" VALUE="{ l.list[l.ndx + 1] }"> <MvASSIGN NAME="l.list" INDEX="{ l.ndx + 1 }" VALUE="{ l.temp }"> <MvASSIGN NAME="l.swapped" VALUE="{ 1 }"> </MvIF> <MvASSIGN NAME="l.ndx" VALUE="{ l.ndx + 1 }"> </MvWHILE> </MvWHILE> <MvFUNCRETURN VALUE="{ l.list }"> </MvFUNCTION>
Insertion SortInsertion Sort is a simple sorting algorithm that is relatively efficient for small lists and partly sorted lists, and often is used as part of more sophisticated algorithms. It works by taking elements from the list one by one and inserting them in their correct position into a new sorted list. The originator of the method is unknown. Many other sorting methods like the Selection sort, and Heap sort are similar to or derivatives of the insertion sort. The Miva Script implementation was coded by Ray Yates. Watch this video to see a Insertion sort in action. Relative speed: 950 elements per sec.Example: Suitable for sorting hundred of items.<MvFUNCTION NAME="Insertionsort" PARAMETERS="list" STANDARDOUTPUTLEVEL=""> <MvCOMMENT> insertionSort(array A) for i = 1 to length[A]-1 do begin value = A[i] j = i-1 while j >= 0 and A[j] > value do begin A[j + 1] = A[j] j = j-1 end A[j+1] = value end </MvCOMMENT> <MvASSIGN NAME="l.maxlist" VALUE="{ miva_array_elements(l.list) }"> <MvASSIGN NAME="l.i" VALUE="{ 2 }"> <MvWHILE EXPR="{ l.i LE l.maxlist }"> <MvASSIGN NAME="l.key" VALUE="{ l.list[l.i] }"> <MvASSIGN NAME="l.j" VALUE="{ l.i - 1 }"> <MvWHILE EXPR="{ (l.j GE 1) AND (l.list[l.j] GT l.key)}"> <MvASSIGN NAME="l.list" INDEX="{ l.j + 1 }" VALUE="{ l.list[l.j] }"> <MvASSIGN NAME="l.j" VALUE="{ l.j - 1 }"> <MvIF EXPR="{ l.j LT 1 }"> <MvWHILESTOP> </MvIF> </MvWHILE> <MvASSIGN NAME="l.list" INDEX="{l.j+1}" VALUE="{ l.key }"> <MvASSIGN NAME="l.i" VALUE="{ l.i + 1 }"> </MvWHILE> <MvFUNCRETURN VALUE="{ l.list }"> </MvFUNCTION>
Quick SortQuickSortArray is built into the Miva Merchant API and is an implementation of the Quicksort developed by Tony Hoare in 1960. Quicksort is a divide and conquer which relies on a partition operation: to partition an array an element called a pivot is selected. All elements smaller than the pivot are moved before it and all greater elements are moved after it. The QuickSortArray() function was implemented by Jonathan Burchmore at Miva Merchant. Watch this video to see a Quick sort in action. Relative speed: 2250 elements per sec.Example: Suitable for sorting a few thousand items.<MvCOMMENT>! \brief Sorts an array using multiple comparisons to break ties The array is sorted using the Quick Sort algorithm. Each element in \em comparisons contains the following members: \li \c subelement The member to sort by, including the leading colon (:) \li \c direction The direction in which to sort Elements are compared using the MivaScript EQ operator according to each element in \em comparisons. If a comparison results in a tie, the next comparison is used. \param[in,out] array The array to be sorted \param left The index of the lowest element of the array to be sorted \param right The index of the highest element of the array to be sorted \param comparisons An array defining the comparisons to be used and the order in which they should be applied \param comparison_count The number of elements in \em comparisons </MvCOMMENT> <MvFUNCTION NAME = "QuickSortArray" PARAMETERS = "array var, subelement, direction" STANDARDOUTPUTLEVEL = ""> <MvASSIGN NAME = "l.comparisons" INDEX = 1 MEMBER = "subelement" VALUE = "{ l.subelement }"> <MvASSIGN NAME = "l.comparisons" INDEX = 1 MEMBER = "direction" VALUE = "{ l.direction }"> <MvEVAL EXPR = "{ QuickSortArray_Sort( l.array, 1, miva_array_elements( l.array ), l.comparisons, 1 ) }"> </MvFUNCTION> <MvFUNCTION NAME = "QuickSortArray_Sort" PARAMETERS = "array var, left, right, comparisons var, comparison_count" STANDARDOUTPUTLEVEL = ""> <MvIF EXPR = "{ l.right LE l.left }"> <MvFUNCTIONRETURN> </MvIF> <MvASSIGN NAME = "l.pivot_index" VALUE = "{ QuickSortArray_Partition( l.array, l.left, l.right, l.left, l.comparisons, l.comparison_count ) }"> <MvEVAL EXPR = "{ QuickSortArray_Sort( l.array, l.left, l.pivot_index - 1, l.comparisons, l.comparison_count ) }"> <MvEVAL EXPR = "{ QuickSortArray_Sort( l.array, l.pivot_index + 1, l.right, l.comparisons, l.comparison_count ) }"> </MvFUNCTION> <MvFUNCTION NAME = "QuickSortArray_Partition" PARAMETERS = "array var, left, right, pivot_index, comparisons var, comparison_count" STANDARDOUTPUTLEVEL = ""> <MvASSIGN NAME = "l.pivot_element" VALUE = "{ l.array[ l.pivot_index ] }"> <MvASSIGN NAME = "l.store_index" VALUE = "{ l.left }"> <MvEVAL EXPR = "{ QuickSortArray_Swap( l.array, l.pivot_index, l.right ) }"> <MvASSIGN NAME = "l.i" VALUE = "{ l.left }"> <MvWHILE EXPR = "{ l.i LT l.right }"> <MvIF EXPR = "{ QuickSortArray_Compare( l.array[ l.i ], l.pivot_element, l.comparisons, l.comparison_count ) LE 0 }"> <MvEVAL EXPR = "{ QuickSortArray_Swap( l.array, l.i, l.store_index ) }"> <MvASSIGN NAME = "l.store_index" VALUE = "{ l.store_index + 1 }"> </MvIF> <MvASSIGN NAME = "l.i" VALUE = "{ l.i + 1 }"> </MvWHILE> <MvEVAL EXPR = "{ QuickSortArray_Swap( l.array, l.store_index, l.right ) }"> <MvFUNCTIONRETURN VALUE = "{ l.store_index }"> </MvFUNCTION> <MvFUNCTION NAME = "QuickSortArray_Compare" PARAMETERS = "left_element var, right_element var, comparisons var, comparison_count" STANDARDOUTPUTLEVEL = ""> <MvASSIGN NAME = "l.comp_pos" VALUE = 1> <MvASSIGN NAME = "l.result" VALUE = 0> <MvWHILE EXPR = "{ l.comp_pos LE l.comparison_count }"> <MvASSIGN NAME = "l.left_value" VALUE = "{ miva_variable_value( 'l.left_element' $ l.comparisons[ l.comp_pos ]:subelement ) }"> <MvASSIGN NAME = "l.right_value" VALUE = "{ miva_variable_value( 'l.right_element' $ l.comparisons[ l.comp_pos ]:subelement ) }"> <MvIF EXPR = "{ l.left_value LT l.right_value }"> <MvFUNCTIONRETURN VALUE = "{ 0 - l.comparisons[ l.comp_pos ]:direction }"> <MvELSEIF EXPR = "{ l.left_value GT l.right_value }"> <MvFUNCTIONRETURN VALUE = "{ l.comparisons[ l.comp_pos ]:direction }"> </MvIF> <MvASSIGN NAME = "l.comp_pos" VALUE = "{ l.comp_pos + 1 }"> </MvWHILE> <MvFUNCTIONRETURN VALUE = 0> </MvFUNCTION> <MvFUNCTION NAME = "QuickSortArray_Swap" PARAMETERS = "array var, a, b" STANDARDOUTPUTLEVEL = ""> <MvASSIGN NAME = "l.temp" VALUE = "{ l.array[ l.a ] }"> <MvASSIGN NAME = "l.array" INDEX = "{ l.a }" VALUE = "{ l.array[ l.b ] }"> <MvASSIGN NAME = "l.array" INDEX = "{ l.b }" VALUE = "{ l.temp }"> </MvFUNCTION>
Array Sort ByArray Sort By is an adaption to the Miva Script function miva_array_sort(), that allows structured arrays to be sorted by MEMBER name. Originally posted by Scott McCollough on 2/4/2011 on the Miva Merchant forum. It correctly sorts numeric values and can sort descending as well as ascending. Relative speed: 5500 elements per sec.Example: Suitable for sorting thousands of items.<MvFUNCTION NAME = "Array_Sort_By" PARAMETERS = "digits, orderby, member, array var" STANDARDOUTPUTLEVEL = ""> <MvCOMMENT> Based on Miva_Array_Sort_By() -- Scott McCollough. Optimized by Ray Yates Forum: http://extranet.mivamerchant.com/forums/showthread.php?103322-MivaScript.com-is-now-LIVE!/page2 Array_Sort_By( Digits, Orderby, Member, Aggregate ) Digits: integer number used for numeric sorting. Used to pad the left of the number with zeros. For integers use 5; For text sorting use 0 or a null string. Orderby: string, 'D' for descending, 'A' or ascending (default if null). Member: string, the name of the field/member to sort by. Aggregate: array, The Array structure passed by reference. It will be altered on return. NOTE: miva_array_sort() Sorts on the alphabetically first member so we create a new member called "A" </MvCOMMENT> <MvIF EXPR="{ (l.digits LT 1 OR l.digits GT 20) AND isdigit(l.digits) }"> <MvASSIGN NAME="l.digits" VALUE=""> </MvIF> <MvASSIGN NAME = "l.orderby" VALUE = "{ toupper(l.orderby) }"> <MvASSIGN NAME = "l.max" VALUE = "{ miva_array_max( l.array ) }"> <MvASSIGN NAME = "l.pos" VALUE = "{ miva_array_min( l.array ) }"> <MvCOMMENT>Add the sort member A</MvCOMMENT> <MvIF EXPR="{ l.digits }"> <MvWHILE EXPR = "{ l.pos LE l.max }"> <MvASSIGN NAME = "l.array" INDEX = "{ l.pos }" MEMBER = "A" VALUE = "{ padl(miva_variable_value( 'l.array[' $ l.pos $ ']:' $ l.member ),l.digits,'0') }"> <MvASSIGN NAME = "l.pos" VALUE = "{ miva_array_next( l.array, l.pos ) }"> </MvWHILE> <MvELSE> <MvWHILE EXPR = "{ l.pos LE l.max }"> <MvASSIGN NAME = "l.array" INDEX = "{ l.pos }" MEMBER = "A" VALUE = "{ miva_variable_value( 'l.array[' $ l.pos $ ']:' $ l.element ) }"> <MvASSIGN NAME = "l.pos" VALUE = "{ miva_array_next( l.array, l.pos ) }"> </MvWHILE> </MvIF> <MvCOMMENT>Sort it.</MvCOMMENT> <MvIF EXPR="{ l.orderby EQ 'D' }"> <MvASSIGN NAME = "l.count" VALUE = "{ miva_array_sort( l.array, 'MA_Sort_Desc', l.null ) }"> <MvELSE> <MvASSIGN NAME = "l.count" VALUE = "{ miva_array_sort( l.array, 'MA_Sort_Asc', l.null ) }"> </MvIF> <MvFUNCTIONRETURN VALUE = "{ l.count }"> </MvFUNCTION> <MvFUNCTION NAME = "MA_Sort_Asc" PARAMETERS = "left var, right var, data var" STANDARDOUTPUTLEVEL = ""> <MvIF EXPR = "{ l.left LT l.right }"> <MvFUNCTIONRETURN VALUE = "-1"> <MvELSEIF EXPR = "{ l.left GT l.right }"> <MvFUNCTIONRETURN VALUE = "1"> </MvIF> <MvFUNCTIONRETURN VALUE = "0"> </MvFUNCTION> <MvFUNCTION NAME = "MA_Sort_Desc" PARAMETERS = "left var, right var, data var" STANDARDOUTPUTLEVEL = ""> <MvIF EXPR = "{ l.left LT l.right }"> <MvFUNCTIONRETURN VALUE = "1"> <MvELSEIF EXPR = "{ l.left GT l.right }"> <MvFUNCTIONRETURN VALUE = "-1"> </MvIF> <MvFUNCTIONRETURN VALUE = "0"> </MvFUNCTION>
Miva_Array_SortThe function miva_array_sort(), as of version 5.07, is built into Miva Script . It is a Bubble sort implimented by Mark Johnson of Miva Merchant. It calls external functions that must be defined within your program and are most commonly used to determine sort order. Relative speed: 8000 elements per sec.Example: Suitable for sorting many thousands of items.<MvCOMMENT>Sort Ascending.</MvCOMMENT> <MvASSIGN NAME = "l.count" VALUE = "{ miva_array_sort( l.array, 'MA_Sort_Asc', l.data ) }"> <MvFUNCTION NAME = "MA_Sort_Asc" PARAMETERS = "left var, right var, data var" STANDARDOUTPUTLEVEL = ""> <MvIF EXPR = "{ l.left LT l.right }"> <MvFUNCTIONRETURN VALUE = "-1"> <MvELSEIF EXPR = "{ l.left GT l.right }"> <MvFUNCTIONRETURN VALUE = "1"> </MvIF> <MvFUNCTIONRETURN VALUE = "0"> </MvFUNCTION> <MvCOMMENT>Sort Descending.</MvCOMMENT> <MvASSIGN NAME = "l.count" VALUE = "{ miva_array_sort( l.array, 'MA_Sort_DESC', l.data ) }"> <MvFUNCTION NAME = "MA_Sort_Desc" PARAMETERS = "left var, right var, data var" STANDARDOUTPUTLEVEL = ""> <MvIF EXPR = "{ l.left LT l.right }"> <MvFUNCTIONRETURN VALUE = "1"> <MvELSEIF EXPR = "{ l.left GT l.right }"> <MvFUNCTIONRETURN VALUE = "-1"> </MvIF> <MvFUNCTIONRETURN VALUE = "0"> </MvFUNCTION>
Gieppner SortThe Gieppner Sort is one of the fastest sort routine available for Miva Script (for many datasets) and an improvement on the original Member_Sort(). Developed by Marcus Gieppner and optimized here by Ray Yates. Originally posted 02/2011 on the Miva Merchant forum as sort_array_by_elements(). It takes advantage of the fact the MivaScript creates array member structures in sorted order using a Splay Tree. This unfortunately limits the characters that can be used in the dataset to alpha-numeric characters plus the underscore. This implementation provides text and numeric sorting, ascending or descending, and can sort by any member in a structured array. Relative speed: 16000 elements per sec.Example: Suitable for sorting large data sets<MvFUNCTION NAME = "Gieppner_Sort" PARAMETERS="number, direction, element, array VAR, returnarray VAR" STANDARDOUTPUTLEVEL = "html,text,compresswhitespace"> <MvCOMMENT> Sorts simple or complex arrays structures. Gieppner_Sort(0, 'A', 'member', array, return) Derived from sort_array_by_element(array VAR,element,direction) User: Marcus Gieppner aka MvMarkus (http://extranet.mivamerchant.com/forums/showthread.php?p=374041#post374041) Parameters number: If number > 0 it designates a numeric sort. If number = 0 a text sort is indicated. The value of number is the expected number of digits to the left of the decimal point. For integers use 5, Long integers use 10, etc. Correctly sorts negative numbers. direction: (string value) Use 'D' for Descending 'A' for Ascending (defaults to Ascending) element: (string value) Designates the array member to sort on array: The array to be sorted returnarray: The sorted </MvCOMMENT> <MvASSIGN NAME="l.number" VALUE="{ int(abs(l.number)) }"> <MvASSIGN NAME="l.element" VALUE="{ trim(l.element) }"> <MvASSIGN NAME="l.direction" VALUE="{ toupper(trim(l.direction)) }"> <MvIF EXPR="{ NOT (l.direction AND ('D' CIN l.direction)) }"> <MvASSIGN NAME="l.direction" VALUE="A"> </MvIF> <MvASSIGN NAME = "l.max" VALUE = "{ miva_array_max( l.array ) }"> <MvASSIGN NAME = "l.pos" VALUE = "{ miva_array_min( l.array ) }"> <MvIF EXPR="{ l.number }"> <MvASSIGN NAME="l.maxnum " VALUE="{ 10 POW l.number }"> <MvWHILE EXPR = "{ l.pos LE l.max }"> <MvASSIGN NAME="l.var" VALUE="{ miva_variable_value('l.array[' $ l.pos $ ']:' $ l.element) }"> <MvCOMMENT>handling negative numbers </MvCOMMENT> <MvASSIGN NAME = "l.str" VALUE = "{ 'A' $ padl(l.maxnum + l.var, l.number + 1, '0') }" > <MvASSIGN NAME = "{ 'l.index:'$l.str }" INDEX="{ miva_array_max(miva_variable_value( 'l.index:'$l.str))+1 }" VALUE = "{ l.pos }" > <MvASSIGN NAME = "l.pos" VALUE = "{ l.pos + 1 }"> </MvWHILE> <MvELSE> <MvCOMMENT>Alpha Numeric (case insensitive)</MvCOMMENT> <MvWHILE EXPR = "{ l.pos LE l.max }"> <MvREFERENCE NAME = "l.v" VARIABLE = "{ 'l.array[' $ l.pos $ ']:' $ l.element }"> <MvASSIGN NAME = "l.str" VALUE = "{ substring(glosub(l.v,' ','_'),1,32) }" > <MvASSIGN NAME = "{ 'l.index:' $ l.str }" INDEX="{ miva_array_max(miva_variable_value( 'l.index:' $ l.str)) + 1 }" VALUE = "{ l.pos }" > <MvASSIGN NAME = "l.pos" VALUE = "{ l.pos + 1 }"> </MvWHILE> </MvIF> <MvASSIGN NAME = "l.index" VALUE = "{ miva_array_deserialize(trim(l.index)) }" > <MvIF EXPR="{ l.direction AND ('D' CIN l.direction) }"> <MvCOMMENT> Descending </MvCOMMENT> <MvASSIGN NAME="l.pos" VALUE="{ 1 }"> <MvASSIGN NAME="l.max" VALUE="{ miva_array_max(l.index) }"> <MvASSIGN NAME="l.ndx" VALUE="{ l.max + 1}"> <MvWHILE EXPR="{ l.pos LE l.max }"> <MvASSIGN NAME = "l.returnarray" INDEX="{ l.pos }" VALUE = "{ l.array[l.index[l.ndx - l.pos]] }" > <MvASSIGN NAME="l.pos" VALUE="{ l.pos + 1 }"> </MvWHILE> <MvELSE> <MvCOMMENT> Ascending </MvCOMMENT> <MvASSIGN NAME="l.pos" VALUE="{ 1 }"> <MvASSIGN NAME="l.max" VALUE="{ miva_array_max(l.index) }"> <MvWHILE EXPR="{ l.pos LE l.max }"> <MvASSIGN NAME = "l.returnarray" INDEX="{ l.pos }" VALUE = "{ l.array[l.index[l.pos]] }" > <MvASSIGN NAME="l.pos" VALUE="{ l.pos + 1 }"> </MvWHILE> </MvIF> </MvFUNCTION>
Member SortMember Sort is the fastest sort routine available for MivaScript. Developed by Marcus Gieppner and originally posted 09/2008 as QSort() on the Miva Merchant forum. It takes advantage of the fact the MivaScript creates array member structures in sorted order using a Splay Tree. This unfortunately limits the characters that can be used in the dataset to alpha-numeric characters plus the underscore. It has no relation to the well known QSort algorithm. It sorts single dimension text arrays in ascending order. Relative speed: 17500 elements per sec.Example: Suitable for sorting large data sets.<MvFUNCTION NAME = "Member_Sort" PARAMETERS="array var, sorted var" STANDARDOUTPUTLEVEL = ""> <MvCOMMENT> by MvMarkus http://extranet.mivamerchant.com/forums/showthread.php?p=82456#post82456 Only works for text sorting ascending order, takes advantage of the fact that Miva Script creates array members alphabetically sorted. </MvCOMMENT> <MvASSIGN NAME = "l.a" VALUE = "1" > <MvASSIGN NAME="l.max" VALUE="{ miva_array_max( l.array) }"> <MvWHILE EXPR = "{ l.a LE l.max }"> <MvIF EXPR = "{ l.array[l.a] }"> <MvASSIGNARRAY NAME="l.sorted_array" VALUE="{ l.array[l.a] }"> <MvMEMBER NAME="{ l.array[l.a] }"> <MvDIMENSION INDEX="{ miva_array_max( miva_variable_value('l.sorted_array:'$ l.array[l.a]))+1 }"> </MvASSIGNARRAY> </MvIF> <MvASSIGN NAME = "l.a" VALUE = "{ l.a+1 }" > </MvWHILE> <MvASSIGN NAME="l.sorted" VALUE="{ miva_array_deserialize(trim(l.sorted_array)) }"> </MvFUNCTION>
Radix Text SortThe Radix Sort allows any character unlike the Gieppner Sort. It is the fastest sort available for Miva Script. The Radix sort is dates back as far as 1887 to the work of Herman Hollerith on tabulating machines used in the US Census. It was originally a numeric sort. This implementation by Ray Yates 09/2011, is a modified Radix sort designed to work with text instead of numbers. Unlike every other sort algorithm presented, it does not swap or even compare array elements. Instead it uses the asciichar values to rapidly determine the correct index position of the sorted array elements. Once an elements sorted position is determined, it is removed from further consideration which speeds up the sort even more. Again has no limitations on the characters set sorted. Watch this video to see a simplified numeric Radix sort in action. To visualize a Radix sort of text, write the letters a-z in a column on a sheet of paper. Seperately take 20 or more words and write each on the row according to the first letter. Next, look at each row with words. If there is only one word, write it to the final list. If there are more than one word, look at the second letter and place each in a new a-z list according to the second letter. Relative speed: 19800 elements per sec.Example: Suitable for sorting very large data sets.<MvFUNCTION NAME="Radix_Sort" PARAMETERS="direction, array var, sorted var" STANDARDOUTPUTLEVEL="" ERROROUTPUTLEVEL="runtime"> <MvCOMMENT> Radix_Sort() is a modified Radix sort designed to work with text instead of numbers. Youtube video: http://www.youtube.com/watch?v=50_TCQGjNJc It does no comparisons, but instead it indexes each word based on the asciichar() code of the first letters then the second letter and so on till the sort position is determined. </MvCOMMENT> <MvIF EXPR="{ NOT (l.direction AND ('D' CIN l.direction)) }"> <MvASSIGN NAME="l.direction" VALUE="A"> <MvELSE> <MvASSIGN NAME="l.direction" VALUE="D"> </MvIF> <MvASSIGN NAME="l.asciiMin" VALUE="{ 255 }"> <MvASSIGN NAME="l.sorted" VALUE=""> <MvCOMMENT> Scan the first letter of each element and create the letterTable Store them based on the asciichar() code "c" as the index in letterTable[c][n] Each n element in letterTable[c][n] contains the index to a word that starts with that letter. When complete every element index is sorted by the first letter. </MvCOMMENT> <MvFOREACH ITERATOR = "l.item" ARRAY = "l.array" INDEX = "l.pos"> <MvIF EXPR="{ l.item }"> <MvASSIGN NAME="l.charcode" VALUE="{ asciivalue(substring(l.item, 1, 1)) }"> <MvASSIGNARRAY NAME="l.letterTable" VALUE="{ l.pos }"> <MvDIMENSION INDEX="{ l.charcode }"> <MvDIMENSION INDEX="{ miva_array_max(l.letterTable[l.charcode]) + 1 }"> </MvASSIGNARRAY> </MvIF> </MvFOREACH> <MvASSIGN NAME="l.asciiMin" VALUE="{ miva_array_min(l.letterTable) }"> <MvASSIGN NAME="l.asciiMax" VALUE="{ miva_array_max(l.letterTable) }"> <MvCOMMENT> Start the recursive indexing of each row </MvCOMMENT> <MvASSIGN NAME="l.level" VALUE="{ 1 }"> <MvFOREACH ITERATOR = "l.tableRow" ARRAY = "l.letterTable" FIRST = "{ l.asciiMin }" LAST = "{ l.asciiMax }"> <MvEVAL EXPR="{ ys_matrix_row(l.level, l.tableRow, l.array, l.index) }"> </MvFOREACH> <MvIF EXPR="{ l.direction AND ('D' CIN l.direction) }"> <MvCOMMENT> Descending </MvCOMMENT> <MvASSIGN NAME="l.pos" VALUE="{ 1 }"> <MvASSIGN NAME="l.max" VALUE="{ miva_array_max(l.index) }"> <MvASSIGN NAME="l.ndx" VALUE="{ l.max + 1}"> <MvWHILE EXPR="{ l.pos LE l.max }"> <MvASSIGN NAME = "l.sorted" INDEX="{ l.pos }" VALUE = "{ l.array[l.index[l.ndx - l.pos]] }" > <MvASSIGN NAME="l.pos" VALUE="{ l.pos + 1 }"> </MvWHILE> <MvELSE> <MvCOMMENT> Ascending </MvCOMMENT> <MvASSIGN NAME="l.pos" VALUE="{ 1 }"> <MvASSIGN NAME="l.max" VALUE="{ miva_array_max(l.index) }"> <MvWHILE EXPR="{ l.pos LE l.max }"> <MvASSIGN NAME = "l.sorted" INDEX="{ l.pos }" VALUE = "{ l.array[l.index[l.pos]] }" > <MvASSIGN NAME="l.pos" VALUE="{ l.pos + 1 }"> </MvWHILE> </MvIF> </MvFUNCTION> <MvFUNCTION NAME="ys_matrix_row" PARAMETERS="level, tableRow var, array var, sorted var" STANDARDOUTPUTLEVEL="" ERROROUTPUTLEVEL="runtime"> <MvCOMMENT> level is the character position we are looking at On first pass. Where l.tableRow[c] is the matrix row for the first letter in each word (e.g. A = chr(65) = index) tableRow[65][1] = index of the first word that starts with A tableRow[65][2] = index of the second word that starts with A tableRow[65][3] = index of the third word that starts with A Where Array[] is the original wordlist Where Sorted[] is the return array. </MvCOMMENT> <MvASSIGN NAME="l.level" VALUE="{ l.level + 1 }"> <MvASSIGN NAME="l.asciiMin" VALUE="{ 255 }"> <MvCOMMENT> If there is only one index in tableRow[], we've found the index postion. Store the word. </MvCOMMENT> <MvIF EXPR="{ miva_array_max(l.tableRow) EQ 1 }"> <MvASSIGN NAME="l.sorted" INDEX="{ miva_array_max(l.sorted) + 1 }" VALUE="{ l.tableRow[1] }"> <MvASSIGN NAME="l.level" VALUE="{ l.level - 1 }"> <MvFUNCTIONRETURN> </MvIF> <MvCOMMENT> Create a new matrix where col contains the index to l.array[] </MvCOMMENT> <MvFOREACH ITERATOR = "l.col" ARRAY = "l.tableRow" INDEX = "l.pos"> <MvCOMMENT> l.array[l.col] is the word. Get the next character.</MvCOMMENT> <MvASSIGN NAME="l.charcode" VALUE="{ asciivalue(substring(l.array[l.col], l.level, 1)) }"> <MvIF EXPR="{ l.charcode }"> <MvASSIGNARRAY NAME="l.rowMatrix" VALUE="{ l.col }"> <MvDIMENSION INDEX="{ l.charcode }"> <MvDIMENSION INDEX="{ miva_array_max(l.rowMatrix[l.charcode]) + 1 }"> </MvASSIGNARRAY> <MvELSE> <MvCOMMENT> This string ran out of characters and can not be further sorted </MvCOMMENT> <MvASSIGN NAME="l.sorted" INDEX="{ miva_array_max(l.sorted) + 1 }" VALUE="{ l.col }"> </MvIF> </MvFOREACH> <MvIF EXPR="{ l.rowMatrix }"> <MvASSIGN NAME="l.asciiMin" VALUE="{ miva_array_min(l.rowMatrix) }"> <MvASSIGN NAME="l.asciiMax" VALUE="{ miva_array_max(l.rowMatrix) }"> <MvCOMMENT> Recursively call the new matrix for the next character </MvCOMMENT> <MvFOREACH ITERATOR = "l.row" ARRAY = "l.rowMatrix" FIRST = "{ l.asciiMin }" LAST = "{ l.asciiMax }"> <MvIF EXPR="{ miva_array_max(l.row) EQ 1 }"> <MvCOMMENT> If there is only one index so we've found the next sorted word </MvCOMMENT> <MvASSIGN NAME="l.sorted" INDEX="{ miva_array_max(l.sorted) + 1 }" VALUE="{ l.row[1] }"> <MvELSE> <MvCOMMENT> More than one matching letter so recursively call the new matrix for the next character </MvCOMMENT> <MvEVAL EXPR="{ ys_matrix_row(l.level, l.row, l.array, l.sorted) }"> </MvIF> </MvFOREACH> </MvIF> <MvASSIGN NAME="l.level" VALUE="{ l.level - 1 }"> </MvFUNCTION>
Binary SearchA binary search or half-interval search finds the position of a specified value within a sorted array. At each stage the search key is compared value with the key value of the middle element of the array. The result is either a match, higher or lower. If no match is found each successive search splits the search area in half and repeats until the index is found and returned. The Miva Script implementation was coded by Ray Yates. Relative speed: Virtually Instant.Example: Suitable for searching sorted data sets of any size.<MvFUNCTION NAME="BinarySearch_By" PARAMETERS="a var, member, key" STANDARDOUTPUTLEVEL=""> <MvCOMMENT> Searches the sorted list A for key, and returns the index if found or 0 Returns the index in the array if found else returns 0, Note: Results are so fast that timing is nearly meaningless. a: the sorted array being searched. member: the optional member name being searched. (e.g. a[n]:member) if null a simple array is expected. key: the search value. <MvASSIGN NAME="l.index" VALUE="{ BinarySearch_By(l.array, l.member, l.search) }"> </MvCOMMENT> <MvASSIGN NAME="l.low" VALUE="{ 1 }"> <MvASSIGN NAME="l.high" VALUE="{ miva_array_elements(l.A) }"> <MvASSIGN NAME="l.found" VALUE="{ 0 }"> <MvWHILE EXPR="{ l.low LE l.high }"> <MvASSIGN NAME="l.mid" VALUE="{ int((l.low + l.high) /2) }"> <MvIF EXPR="{ l.member }"> <MvREFERENCEARRAY NAME = "l.element" VARIABLE = "l.A"> <MvDIMENSION INDEX = "{ l.mid }"> <MvMEMBER NAME= "{ l.member }"> </MvREFERENCEARRAY> <MvELSE> <MvREFERENCEARRAY NAME = "l.element" VARIABLE = "l.A"> <MvDIMENSION INDEX = "{ l.mid }"> </MvREFERENCEARRAY> </MvIF> <MvIF EXPR="{ l.element GT l.key }"> <MvASSIGN NAME="l.high" VALUE="{ l.mid -1 }"> <MvELSEIF EXPR="{ l.element LT l.key }"> <MvASSIGN NAME="l.low" VALUE="{ l.mid + 1 }"> <MvELSE> <MvASSIGN NAME="l.found" VALUE="{ l.mid }"> <MvWHILESTOP> </MvIF> </MvWHILE> <MvFUNCRETURN VALUE="{ l.found }"> </MvFUNCTION>
|