November 14, 2024

The Ham Sort

Sorting amateur call signs [like the Callbook listings] can be tricky.  If you want to sort by call district, then by suffix, and finally by prefix then there is a little bit of string manipulation to be done.  In the left column below, you will see a random assortment of call signs.  In the right column, you see them after they are sorted with this method.

AA2AW0HSI
WB4AEJKN0SCC
WA4ZZQAA2A
K9FQLWB4AEJ
KN0SCCWA4ZZQ
DK7UYKD5DTE
W8CAW7DK
KD5DTEDK7UY
W0HSIW8CA
W7DKK9FQL

I originally wrote this sort using Perl.  However, there is no reason it couldn’t be incorporated into any other scripting or programming language.  Let me explain the structure.

When examining a variable containing a callsign, the first step is to determine whether the third and/or the second item in the element is a digit (0-9).  First check the third one as some calls have numerals in both places.  If both the third and second one are digits, treat the numeral of the second character as a letter.  In W1AW, the digit is the second character.   In T93Y, the second and third characters are digits. We will use the third character to sort on and treat the second character as a letter (even though it is a numeral).  In WB4AEJ or NN8L, it is the third character.

At this point, you have to use if statements so that each of these calls are processed separately.

W1AW first must be changed to 1AW#W# (the ‘#’ represents a non-existent character).

WB4AEJ must be changed to 4AEJWB.  NN8L must be changed to 8L##NN.  T93Y must be changed to 3Y##T9.

Now, concatenate them together like this (using an ampersand as a delimiter):

  • 8L##NN&NN8L
  • 4AEJWB&WB4AEJ
  • 1AW#W#&W1AW
  • 3Y##T9&T93Y

Now, you must simply sort the list using the sort() function.

  • 1AW#W#&W1AW#
  • 3Y##T9&T93Y
  • 4AEJWB&WB4AEJ
  • 8L##NN&NN8L

The final step in this process is to drop the first element in each line (everything before and including the
ampersand) yielding:

  • W1AW
  • T93Y
  • WB4AEJ
  • NN8L

You will now notice that all of the above are listed in the Callbook order.

The question probably arises, “Why the blank spaces (represented by a ‘#’)?”.   The answer to that is that if you don’t place them when required (which is when your suffix is less than three alphabetic characters), sorting can become corrupted.  Example: NN8L and W8LAP.  When I first developed the sort (without the blank spaces), these two returned from the sort with W8LAP before NN8L.  By changing NN8L to 8LNN and sorting it with W8LAP becoming 8LAPW, W8LAP improperly appeared before NN8L.

I solved this problem by forcing three suffix characters after the digit and two for the prefix.  If there were not three characters in the suffix, I kept adding the ‘#” after the suffix until the suffix and the spaces became a total of three characters.  If the prefix was only one character, I added ‘#’ after it.  Thus NN8L yields 8L##NN and W8LAP yields 8LAPW#.  As a ‘#’ is treated as a higher ASCII value than an A, a blank space wins out on the sort over an alphanumeric character.  T93Y comes before 3Y#T9.  To be sure it will sort correctly, there should always be six characters before you begin the sort.  Problem solved.

If the prefix has only one character, I add a blank as well.  Here is an example of the sort written in PERL:

$numeral = substr($call,1,1);
if ($numeral =~ /\d/) {      
$temp = substr($call,0,1);      
$hl = length ($temp);      
if ($hl < 4) {            $temp = $temp . ” “;            
$hl = length ($temp);       }      
$temp = $temp . substr($call,0,1);      
$log[$count] = $temp . “&” . $log[$count];
} else {      $temp = substr($call);      
$hl = length ($temp);      
if ($hl < 4) {         
$temp = $temp . ” “;          
$hl = length ($temp);      }      
$temp = $temp . substr($call,0,2); }      
$callsortstring = $temp . “&” . $call;

I have created a PHP function that changes a callsign into a format that can be sorted to arrive at Callbook like order.

<?php
  $callsign = array(“W3A”,”W1AW”,”W4ABC”,”AE4J”,”AC4RI”,”WB4AEJ”,”NN3SI”);
  $m = 0;
  $m1 = 1;
  while($m < count($callsign)) {
    echo $callsign[$m] . ” is call $m1 of a total of ” . count($callsign) . “.<br>\n”;
    $sortcode = callbook($callsign[$m]);
    echo “The returned sortcode is: $sortcode.<br>\n”;
    echo “&lthr>\n”;
    $m++;
    $m1 = $m + 1;
  }
  die(“End of Process.<br>\n”);
  function callbook($call)
  /* The function callbook is copyrighted by Fred Atkinson. The function
  callbook should not be altered in any way.
 https://www.wb4aej.com/hamsort */
  {
    if (substr($call,2,1) >= ‘0’ && substr($call,2,1) <= ‘9’) {
      $sort = substr($call,2,1) . substr($call,3,3);
      $slength = strlen($sort);
      while($slength<4) {
        $sort .= “#”;
        $slength = strlen($sort);
      }
    $prefix = substr($call,0,2);
    $plength = strlen($prefix);
    $sort .= $prefix;
    $slength = strlen($sort);
    while($slength<6) {
      $sort .= “#”;
      $slength = strlen($sort);
      }
    } elseif (substr($call,1,1) >= ‘0’ && substr($call,1,1) <= ‘9’) {
      $sort = substr($call,1,1) . substr($call,2,3);
      $slength = strlen($sort);
      while($slength<4) {
        $sort .= “#”;
        $slength = strlen($sort);
      }
      $prefix = substr($call,0,1);
      $plength = strlen($prefix);
      $sort .= $prefix;
      $sort .= “#”;
      $slength = strlen($sort);
      $prefix = substr($call,0,1);
      $plength = strlen($prefix);
    } else {
      die(“This is not a valid callsign”);
    }
  return $sort;
  }
?>

The PHP function ‘callbook’ will return a sort code that can be put into a separate field in a MySQL (or other type of) database.  Once you have sorted on this field, the records are in Callbook order.

Previously, I used a space to fill in the characters in the sort.  I discovered that MySQL tends to truncate spaces on the end.  I found that the # character does the job just as well.  So if you are sorting callsigns in a database, this function will help you.

Last Updated on March 13, 2021!

Contact me!