I am starting to understand the for loops, but I gathered the information as row 1 would be artist, row 2 would be album, row 3 would be track name, etc. I see that you are doing this by column, at least I think that's what you're doing. It isn't just sorting the array, it's also finding the unique items in the row, or in your example by column. So you could say that each column could be the key? Could you also accomplish this by row? I was actually getting the unique list in an array way bigger than it needed it to be, then when I iterate through it, I look for the empty column to trigger a break in the while loops. I think it works just as fast, but when I examine for say, track names under an artist, I would loop through the whole row. One reason I do this is because there is something really stupid in iTunes. If you have an artist like doors, and some artist tracks are called The Doors, with the word the in it, it can sometimes throw this right in the middle of the artist list depending on the album name. This is just how iTunes sorts some stuff, which is better actually, but harder to program for. So I just loop through the whole row looking for the instances that match. In the last function view all tracks, it does this. I had to also be careful of vertical bars in the genre, artist, album, and track name, which is why I run it through the alphabetize statement to replace those characters. It only detects for single vertical bars and doubles. Anything beyond that in a row is going to mess up the list when it presents itself. So what I am getting around to is being able to count for unique arrays taking out all the duplicates and just leaving it at its monsterous size. If I was able to resize it, could I then count without iterating through a for or while loop? Thanks, John -----Original Message----- From: jawsscripts-bounce@xxxxxxxxxxxxx [mailto:jawsscripts-bounce@xxxxxxxxxxxxx] On Behalf Of Andrew Hart Sent: Wednesday, April 04, 2012 8:21 AM To: jawsscripts@xxxxxxxxxxxxx Subject: [jawsscripts] JAWS Sorting Library 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|frog" ; 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