This is interesting indeed. How long has "optional" been available? On Wed, Apr 04, 2012 at 10:21:14, Andrew Hart wrote: > > Hi folks, > > Recently we've been discussing sorting in JAWS. Here's a small library > of code I have written for doing fast sorting in JAWS. It may be > possible to make the code faster, but this is a good start. I'll paste > the code below, but before I do that, perhaps I'll just give a brief > explanation of how to use it. > > The function that does the sorting is called HeapSort. There are two > helper functions HeapSort uses, Heapify and SiftDown. There are two > utility functions for converting from segmented strings to string arrays > and back again: SegmentedStringToArray and ArrayToSegmentedString. The > final two functions are samples that you can play with to see how it all > works: HeapsortSample1 and HeapsortSample2. > > To see it working, just paste the code into a jss file, dump one or both > of the sample functions into a script, assign the script a key, compile > and try it out. > > I've tried to make the code fairly generic so it can just be added to > existing scripts and used without modification. However, if you are > doing something really special, the paradigm I've used may not suffice > and you'll have to get in and hack things to fit your purpose. > So, here's how you use it. Suppose you have something you want to sort. > You first create a StringArray, say, keys, and fill it with a set of > sort keys corresponding to what you want to sort. If we use John's > project as an example, he has a large 8 column array. For the purpose > of exposition I'll call it tuneData. tuneData is, say, 2000 by 8. If > one of those columns contains the album title and we want to sort the > data by album, we would create a one-dimensional array containing the > album titles using code like > > keys = New StringArray[2000] > For i = 1 To 2000 > keys[i] = tuneData[i, 2] ; supposing that the album title is the > second column of tuneData > endFor > > We also need to declare an IntArray to hold the result of the sort. > Var IntArray indices > > Now we're ready to sort, which is done with the statement > Heapsort(keys, 2000, indices) > > That's it. indices now holds the indices to keys but sorted into their > correct order. Note that Heapsort does not modify the keys array. The > indices array that it returns tells you how to arrange the items in keys > so that they are in lexicographic order. So, if you were to examine > keys[indices[1]], keys[indices[2]], keys[indicies[3]], etc., you'd find > them in order. > > I haven't written a utility function for applying indices to keys, > because it depends on what it is you are sorting. For example, > rearranging a simple StringArray like keys in this example is different > from rearranging the rows of tuneData. I've left this for the > programmer to write, but here's an example of how to do it: > > Var tuneDataSorted = New VariantArray[2000, 8] > For i = 1 To 2000 > For j = 1 To 8 > tuneDataSorted[i, j] = tuneData[indices[i], j] > EndFor > EndFor > > I should probably write a couple of functions for handling stock > standard cases of sorting segmented strings and string arrays so they > can just be used as black boxes, but I haven't had time to do that as yet. > > I hope this is enough info to get anyone interested started in playing > with it. > > Now, here comes the code library, just after my sig. Btw, I also have > a jsd file for these scripts, since I compiled them in a sortlib.jsb and > simply invoked the Use statement to import them into my test scripts. > If anyone wants the jsd file, just let me know. > > Cheers, > Andrew. > > > ; JAWS Sorting Library > ; andrew Hart (April 2012) > > ; *** Heap sort *** > > Void Function HeapSort(StringArray keys, Int arrayLen, IntArray ByRef > indices) > Var > Int i, ; integer counter > Int nIdx ; temp Int for swapping > Let indices = new IntArray[arrayLen] > ; Set up the original indices > For i = 1 to arrayLen > Let indices[i] = i > EndFor > Heapify(keys, arrayLen, indices) ; organise the array into a binary heap > Let i = arrayLen > While i>1 > ; swap the root node (index 1) with the last node in the heap (index i) > Let nIdx = indices[i] > Let indices[i] = indices[1] > Let indices[1] = nIdx > Let i = i - 1 ; decrement i to shrink the heap by one, removing the > last element from the heap and thus leaving it sorted > SiftDown(keys, 1, i, indices) ; sift the new root node into the > correct place in the heap, since it will most probably be in the wrong place > EndWhile > EndFunction > > Void Function Heapify(StringArray heap, Int nEnd, IntArray indices) > ; Organise the indices array so that when the array "heap" is ordered > according to it, we obtain a heap. > ; A heap is a tree in which each node is larger than (or is ranked as > coming after) any of its children. > Var > Int nStart > Let nStart = (nEnd-2)/2 + 1 ; find the last parent node in the heap > While nStart>=1 ; while we haven't processed the root node of the tree > SiftDown(heap, nStart, nEnd, indices) ; sift the current node down the > tree until it is larger than any of its children > Let nStart = nStart-1 ; move to the next node that we haven't sifted yet > EndWhile > ; That's it. The indices and heap arrays now encode a heap structure. > EndFunction > > Void Function SiftDown(StringArray heap, Int nStart, Int nEnd, IntArray > indices) > Var > Int nLeftChild, ; for holding the index of the left child of the root > Int nSwap, ; for holding the swap index > Int nRoot, ; for holding the root index > Int nIdx ; temp Int for facilitating swap > If nStart<1 || nStart>nEnd Then ; trap caller stupidity so JAWS doesn't > go tropo > Return > EndIf > Let nRoot = nStart ; set the root to the start node specified by the caller > While nRoot*2<=nEnd > Let nSwap = nRoot ; initially set the swap index to the root index > nLeftChild = nRoot*2 ; get the index of the root's left child node > If StringCompare(heap[indices[nSwap]], heap[indices[nLeftChild]])<0 ; > if the root is smaller than it's left child > Let nSwap = nLeftChild ; make the left child the swap target > EndIf > If nLeftChild<nEnd then ; if the root has a right child node > If StringCompare(heap[indices[nSwap]], > heap[indices[nLeftChild+1]])<0 Then ; if the currently selected swap > target is smaller than the root's right child > Let nSwap = nLeftChild+1 ; make the right child the swap target > EndIf > EndIf > ; Decide whether or not to swap > If nRoot!=nSwap Then ; if the swap target is no longer the root node > ; exchange the root and swap nodes > Let nIdx = indices[nSwap] > Let indices[nSwap] = indices[nRoot] > Let indices[nRoot] = nIdx > Let nRoot = nSwap ; make the swap node the root and repeat to > continue sifting the root down the branch > Else > Return ; heap property recovered, done sifting, bail out here > EndIf > EndWhile > EndFunction > > > ; *** Utility functions for converting back and forth between segmented > strings and string arrays *** > > String Function ArrayToSegmentedString(StringArray a, Int arraylen, > String sep, optional IntArray indices) > Var > Int i, > String s > If indices[1]<1 ; if no indices array is passed in > Let indices = New IntArray[arrayLen] > For i = 1 To arrayLen > indices[i] = i > endFor > EndIf > Let s = a[indices[1]] > For i = 2 to arrayLen > Let s = s + sep + a[indices[i]] > EndFor > Return s > EndFunction > > Int Function SegmentedStringToArray(String segString, String sep, > StringArray ByRef a) > Var > Int i, > Int segCount > Let segCount = StringSegmentCount(segString, sep) > Let a = New StringArray[segCount] > For i = 1 to segCount > Let a[i] = StringSegment(segString, sep, i) > EndFor > Return segCount > EndFunction > > > ; *** Sample Code and Example Code *** > > Const > testarraylen = 10000 ; number of items to sort in HeapSortSample1 > > Void Function HeapSortSample1() > Var > Int i, ; a counter > Int j, ; used as a counter and to hold a boolean value during testing > String s, ; a string > StringArray testarray, ; the array of sort keys > IntArray perm ; the array to hold the indices output by the sort > ; Build a string containing 500 b's > Let s = "" > For j = 1 To 500 > Let s = s+"b" > endFor > ; Create the test array and fill it with something to sort > Let testarray = new StringArray[testarraylen] ; create an array of > testarraylen elements > ; fill the test array with keys > for i = 1 To testarraylen > Let testarray[i] = IntToString(testarraylen+1-i)+s > EndFor > ; Now perform the sort > SayString("starting") ; announce start > Let i = GetTickCount () ; record starting time > heapSort(testarray, testarraylen, perm) ; do the sort > SayInteger(GetTickCount()-i) ; announce the number of ticks that elapsed > during the sort. 1 tick = 1 ms > SayString("done") ; announce done > ; Check to see if the perm array holds the indices sorted into > lexicographic order > Let j = 1 ; set j to True > For i = 1 To testarraylen-1 > Let j = j && (StringCompare(testarray[perm[i]], testarray[perm[i+1]])<=0) > EndFor > If j Then > SayString("Sort successful") > Else > SayString("Sort failed") > EndIf > EndFunction > > Void Function HeapsortSample2() > Var > String s, ; the initial segmented string to sort > String sorted, ; the resulting segmented string > Int nKeys, ; the number of keys in the keys array > StringArray keys, ; array for holding the sort keys > IntArray indices ; the sorted key indices output by Heapsort > Let s = > "dog|rat|pig|cat|bat|ant|owl|ox|tiger|elephant|fish|whale|snake|llama|fro > g" > ; convert to a string array of sort keys > Let nKeys = SegmentedStringToArray(s, "|", keys) > HeapSort(keys, nKeys, indices) ; do the sort > Let sorted = ArrayToSegmentedString(keys, nKeys, "|", indices) ; build a > segmented string from the keys array > DlgSelectItemInList(sorted, "Animal Names", 0) > EndFunction > > > __________� > > View the list's information and change your settings at > //www.freelists.org/list/jawsscripts __________� View the list's information and change your settings at //www.freelists.org/list/jawsscripts