Sort.h
Sort.h
is a library extension contributed by Christopher Tate. It is
versatile in that the one routine can be used to arrange objects or
values in a number of ways (increasing/decreasing order,
alphabetical/reverse alphabetical order, etc.)- all depending on which
routine you have it call. It uses the
Bubble Sort method of sorting.
The extension itself
Following is the code in its entirety, allowing you to cut and paste it into your own file or take a look at its workings:
!\-----------------------------------------------------------------------
Sorting arrays of objects in Hugo
Copyright 2001 by Christopher Tate <ctate@acm.org>
A "comparison routine", as used here, is a routine that returns
non-zero when the order of its two arguments should be
swapped. The arguments are always passed in the order they
currently appear in the array.
For example, if you want to sort the array by the objects'
"height" property in such a way that the shortest object -- the
one with the smallest "height" -- is first, you could use this
comparison routine:
routine AscendingHeightComparison(obj1, obj2)
{
return (obj1.height > obj2.height)
}
If obj1's height is greater than obj2's, it means that the taller
object currently appears earlier in the array, so the two elements
should be swapped.
Assuming that your array of objects is called "lineup" and the
number of objects in the array is in the variable "num_suspects,"
you would sort the array like this:
SortArray(lineup, num_suspects, &AscendingHeightComparison)
Note that you need the '&' character to indicate that the argument
is the address of the comparison routine, not the result of running it.
-----------------------------------------------------------------------\!
#ifclear _SORT_H
#set _SORT_H
!-----------------------------------------------------------------------
! SortArray() arguments:
!
! data = array to sort
! num = number of elements in the array
! comp_routine = the address of the comparison routine to use
routine SortArray(data, num, comp_routine)
{
local i
local did_swap
for (i = 0; i < num; i = i + 1)
{
local j
did_swap = false
for (j = num - 1; j > i; j = j - 1)
{
local swap
swap = call comp_routine(array data[j-1], array data[j])
if swap
{
local tmp
tmp = array data[j]
array data[j] = array data[j-1]
array data[j-1] = tmp
did_swap = true
}
}
! if we didn't swap any elements, then the array is sorted
if not did_swap : return
}
}
!-----------------------------------------------------------------------
! SORT_ASCENDING() and SORT_DESCENDING()
!
! These simple comparison routines are provided to handle the
! common cases of sorting a numeric array in ascending or
! descending order. For example, to sort an entire numeric array
! called "data" in ascending order, just do this:
!
! SortArray(data, data[], &SORT_ASCENDING)
routine SORT_ASCENDING(obj1, obj2)
{
return (obj1 > obj2)
}
routine SORT_DESCENDING(obj1, obj2)
{
return (obj1 < obj2)
}
#endif
As you can see, it is set up to be #include
‘d like any other optional
library file.
How to call
To reiterate, to sort an array of numbers in descending order, one would have this is in the code:
SortArray(array_comprised_of_number_values, number_of_elements_in_array, &SORT_DESCENDING)
Sorting objects by property value will require new routines. A routine
that sorts by character.weight
value would look like:
routine HeavyToLight(obj1, obj2)
{
return (obj1.weight < obj2.weight)
}
In that example, the array would be filled with pointers to the objects themselves instead of just numbers.
Unofficial additions
Alphabetical order
Like we said in the introduction, Sort.h
can be used for sorting
object.name
’s or other string properties by alphabetical order.
Following are two additional routines that use
StringCompare to do so. If sorting a
property other than name
, change the code where applicable.
! We'll need an additional string array so we can properly compare uppercase strings
! to lowercase strings
array lowercase[10] ! will compare up to 10 characters of string; use more or less if you want
routine SortAlphNames(obj1, obj2)
{
local len, k
len = string(lowercase, array obj2.name, 10)
for (k=0; k<len; k=k+1) ! the actual case-conversion loop
{
if lowercase[k] >= 'A' and lowercase[k] <= 'Z'
lowercase[k] = lowercase[k] + ('a'-'A')
}
len = string(_temp_string, array obj1.name, 255)
for (k=0; k<len; k=k+1) ! the actual case-conversion loop
{
if _temp_string[k] >= 'A' and _temp_string[k] <= 'Z'
_temp_string[k] = _temp_string[k] + ('a'-'A')
}
if StringCompare(lowercase,_temp_string) = -1
return 1
else
return 0
}
! The routine doesn't need to return with some kind of comparison statement
! Returning true or false works just as well
Reverse alphabetical order
routine SortReverseAlphNames(obj1, obj2)
{
local len, k
len = string(lowercase, array obj2.name, 10)
for (k=0; k<len; k=k+1) ! the actual case-conversion loop
{
if lowercase[k] >= 'A' and lowercase[k] <= 'Z'
lowercase[k] = lowercase[k] + ('a'-'A')
}
len = string(_temp_string, array obj1.name, 255)
for (k=0; k<len; k=k+1) ! the actual case-conversion loop
{
if _temp_string[k] >= 'A' and _temp_string[k] <= 'Z'
_temp_string[k] = _temp_string[k] + ('a'-'A')
}
if StringCompare(lowercase,_temp_string) = 1
return 1
else
return 0
}
Random order
Here is a quick routine just for shaking things up:
routine SORT_RANDOM(obj1, obj2)
{
return (random(2) - 1)
}
See also: SortProp