Definition: | sequence s = tagset(integer lim, start=1, step=1) |
Description: |
When passed a single parameter (by far the most common use) returns a sequence of integers: {1,2,3,..,lim}.
The optional start and step parameters are reasonably intuitive, as long as you remember that start is after lim, eg tagset(20,10,2) returns {10,12,14,16,18,20}. |
Comments: |
This routine is particularly useful when performing a tag sort, but can freely be used for other purposes.
A tag sort reorders a list of indexes but leaves the data they refer to completely unaltered. When step is non-1, the result is not guaranteed to contain lim, eg tagset(25,21,3) ==> {21,24}. When start=lim the result is always of length 1. Negative steps are also permitted, with obvious consequences for start and lim, eg tagset(24,28,-2) ==> {28,26,24}. If start is greater than lim and step is positive the result is always an empty sequence, likewise when start is less than lim and step is negative. All inputs must always be integers, and every element of the output is always an integer. |
Example Program: |
sequence Names = {"C. C. Catch", "Army of Lovers", "Boney M.", "Dschinghis Khan"} sequence Years = { 1985, 1987, 1975, 1979 } function by_year(integer i, integer j) integer res = compare(Years[i],Years[j]) if res=0 then res = compare(Names[i],Names[j]) end if return res end function sequence yeartags = custom_sort(routine_id("by_year"),tagset(length(Years))) for i=1 to length(yeartags) do integer ti = yeartags[i] printf(1,"Year: %d, Name: %s\n",{Years[ti],Names[ti]}) end for This program, with a sort by name as well as by year, is included in the distribution as demo\tagsort.exw Despite any apparent simplicity, the humble tag sort can be extremely powerful once fully mastered, and just as importantly minimises unintended side effects. |
Another Example: |
sequence Cases = {"Case 3", "caSe 1", "cAse 4", "casE 2"} sequence cases function case_insensitive(integer i, integer j) return compare(cases[i],cases[j]) end function cases = lower(Cases) -- take a modified copy, may warrant loop/string tests. --cases = Cases -- result is 3412, as expected with 'Z' < 'a'. --cases = upper(Cases) -- same result (1234) as using lower, obviously. sequence casetags = custom_sort(routine_id("case_insensitive"),tagset(length(cases))) for i=1 to length(casetags) do printf(1,"%s\n",{Cases[casetags[i]]}) end for This example is also included in demo\tagsort.exw Obviously on a large dataset, this method would be significantly faster than calling upper() or lower() (twice) for each comparison. |