MC: Alphabetize a String

The Challenge

From: joehorn@jps.net
Newsgroups: comp.sys.hp48
Subject: MC: Alphabetize a word

Another Mini-Challenge for the brilliant but bored:

Sneak preview of tonight's HP48 Programming Class assignment:
Sort the characters in a string ("A" to "Z" only) into ASCII order.

Example: "BAZAAR"  -->  "AAABRZ"

Winner: smallest bytes * seconds * clockspeed, as tested on a
huge string (500 to 1000 bytes) with many repeated characters.
All the usual Mini-Challenge rules apply.  Happy Programming!

-Joe-


The Entries
Scroll down a few lines if you really want to see the entries

 

 

 

 

 

 

From: <patrickd@cmdnet.lu> (DOSTERT Patrick)
Subject: Re: MC: Alphabetize a word
Date: Sun, 08 Mar 1998 09:50:22 GMT

\<<
"A" +
[ 0 ] { 26 } RDM OBJ\-> DROP 27 ROLL
1 OVER SIZE 1 -
START
  DUP HEAD NUM 63 - ROLL LASTARG SWAP 1 + SWAP ROLLD TAIL
NEXT
DROP
""
"A" NUM "Z" NUM
FOR I
  SWAP
  IF DUP
  THEN
    1 SWAP
    I CHR 4 ROLLD
	START
	  OVER +
	NEXT
	SWAP
  END
  DROP
NEXT
\>>


222.5 bytes, under one minute with 1024 chrs string (on gx)

From: <painvtqm@worldnet.att.net> (Robert Bellman)
Subject: Re: Alphabetize a word
Date: 8 Mar 1998 19:44:37 GMT

Not that I expect to really compete, but here's mine:

<< "" DUP DUP2 4 DUPN 8 DUPN 10 DUPN 27 ROLL 1 OVER SIZE 1 SWAP
START DUP2 DUP SUB DUP NUM DUP 60 - ROLL 3 ROLL + SWAP 62 - ROLLD 1 + 
NEXT
DROP2 1 25 
START SWAP + 
NEXT
>>

160 BYTES.  It takes about 42 seconds on my GX to do a 1024 character
string.  String may only contain A-Z, no spaces or anything else - although
these could be handled with slight modifications.

Now, I have to get back to my REAL homework and studying for my finance
test next Thursday! :-)

Yours,
Robert Bellman, Jr.

From: dkw@wolferts.sub.de (Klaus Wolferts)
Subject: Re: MC: Alphabetize a word
Date: Sat, 07 Mar 98 23:46:15 -1

Nice challenge, here my solution:

\<< 1 OVER SIZE 
  FOR i DUP i DUP SUB SWAP 
  NEXT SIZE \->LIST SORT OBJ\-> 2 SWAP 
  START + 
  NEXT 
\>>

Checksum #71DEh, 67 bytes

Not really fast ( <3 s for a 50 char string), but rather short ;-) 
Needs 6 bytes/char space for the growing stack, so dont try really huge
strings with only little ram space left ;-)

Klaus
-- 
 dkw@wolferts.sub.de | Dr.-Ing. Klaus Wolferts 
 Tel: +49 721 706016 | Ingenieurbuero fuer EDV + Elektronik 
 Fax: +49 721 706017_|_Mitteltorstr. 45, D-76149 Karlsruhe (Nrt)

From: <postbus@jarno.demon.nl> (Jarno Peschier)
Subject: Re: MC: Alphabetize a word
Date: Tue, 10 Mar 1998 10:10:51 GMT

[regarding the above entry]

You can simply replace the OBJ-> 2 SWAP START + NEXT with one
SigmaLIST command. This gives you # 9BB8h, 52 bytes.

Of course it depends on how exactly to interpret the challenge if this
is solution to the MC or not. If the "("A" to "Z" only)" part was
meant as "the input string only contains A to Z" or "the program
should only take the characters A to Z from the input string and sort
those". (I'm really not sure yet, though I suspect the former which
means your short solution is a valid solution.)


Jarno Peschier, who has recently changed his email address!
 mailto:postbus@jarno.demon.nl   http://jarno.home.ml.org/

From: <wndalouise@aol.com> (WndaLouise)
Subject: Re: Alphabetize a word
Date: 8 Mar 1998 22:10:06 GMT

slightly shorter, much much slower...

<< { } 1 3 PICK SIZE
FOR $ OVER $ $
SUB +
NEXT SORT OBJ-> 2 
START + -1 
STEP SWAP DROP
>>

it took nearly 40 minutes !!! for a 1000 character string...

From: <dlr@mediaone.net> (Douglas L. Rohm)
Subject: Re: Alphabetize a word
Date: Sun, 8 Mar 1998 22:25:26 -0500

Here goes nothing.  I know this isn't the fastest, but it was my first go at
it.

<<
    DUP SIZE 2 SWAP FOR i DUP HEAD SWAP TAIL
    NEXT DEPTH ->LIST SORT ZLIST
>>

* ZLIST = List Sum Command.  MTH LIST menu.  Page 3-170 in Advanced Users
Reference Manual and page G-24 in the Users Manual.

68.0 bytes.  Checksum is #DA50h.  Program took 1261569.41 ticks and
154.00_secs for a 1024 character string on a GX.  Two and a half minutes
ain't too bad.  I used TIM from the Hack Library to time this.  This is my
first time doing the Mini-Challenge, hope I did ok.

Douglas L. Rohm
dlr@mediaone.net

From: <postbus@jarno.demon.nl> (Jarno Peschier)
Subject: Re: Alphabetize a word
Date: Tue, 10 Mar 1998 12:57:07 GMT

[regarding the above entry]

You don't seem to use the loop variable i anywhere, so why not replace
the "FOR i" with "START" and save the space and time of that explicit
loop variable?

Jarno Peschier, who has recently changed his email address!
 mailto:postbus@jarno.demon.nl   http://jarno.home.ml.org/

From: <wndalouise@aol.com> (WndaLouise)
Subject: Re: Alphabetize a word
Date: 9 Mar 1998 06:29:18 GMT

Asort
Alaphabetical Sorter

Sorts a list of 1000 target characters in about 72 seconds.

265 * 72 * 3.754976 = 71644.94208

Asort deviates from the pure assignment in that it checks for both capital and
lowercase target letters, and satanic non-target characters as well, which it
sticks on the end of the returned string.

input: 
1:   "string of characters"
output:
1:   "semi-alphabetized string of characters"

1:   "BpmacJA.2aNx-gH"
Asort
1:   "aAaBcgHJmNpx.2-"

Asort
# F146h
265 bytes

%%HP: T(3)A(D)F(.);
\<< 1 27
  START ""
  NEXT
"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
29 ROLL 1 OVER SIZE
  START DUP2 HEAD
SWAP OVER POS 2 /
DUP
    \<< 4 + DUP ROLL
ROT + SWAP 2 -
ROLLD
    \>>
    \<< DROP 30 ROLL
SWAP + 29 ROLLD
    \>> IFTE TAIL
  NEXT DROP2 1 26
  START SWAP +
  NEXT
\>>

From: <danli97@ite.mh.se> (Daniel Lidstrom)
Subject: Re: MC: Alphabetize a word
Date: Tue, 10 Mar 1998 03:25:14 -0600

Here is my best attempt:

<< "" DUP 1 12
   START DUP2
   NEXT 27 ROLL 1
OVER SIZE START DUP
HEAD DUP NUM 61 - DUP
ROLL ROT + SWAP 2 -
ROLLD TAIL
   NEXT DROP
26 ->LIST
<< SWAP + >>
STREAM
>>
Size: 153.5 checksum: # 4676h Time:52.7 (3.92)
=> bytes*time*speed = 31727

The string was created by this sequence:
1000 "" 1 ROT START RAND 26 * CEIL 64 + 0 RND CHR + NEXT

Daniel Lidstrom,
danli97@ite.mh.se
http://www.ite.mh.se/~danli97/

From: <jhmeyers@miu.edu> (John H Meyers)
Subject: Re: MC: Alphabetize a word
Date: 11 Mar 1998 06:31:49 GMT

Here is a method along lines suggested before, but using an
array of reals to keep character counts, rather than actually
keeping the characters themselves; by using 256 reals,
we can in fact sort the characters of an arbitrary string,
which is what I have actually done and timed here.

In "real life," one is often interested in character frequencies,
but I haven't yet seen a practical application for
keeping the string of re-arranged characters :)

As to comparing timings, everyone may have different amounts
of free memory, different card slots filled, and perhaps even
differently skewed "random" character strings, so the basis
for comparisons is not very exact, even if CPU speed is
already factored in (I didn't bother here).


Stack contents for first part (counting characters):

  "string" [ counters ]

Stack contents for second part (building result string):

  [ counters ] "result string"  (outer FOR loop)

  [ counters ] "current character" "result string"  (inner START loop)


%%HP: T(3);
\<< 2 8 ^ 1 \->LIST 0 CON OVER SIZE 1 SWAP FOR n
  OVER n DUP SUB NUM 1 + DUP2 GET 1 + PUT NEXT
  @ Character-counting is done above; building output string below:
  "" 1 2 8 ^ FOR n OVER n GET DUP
  { n 1 - CHR ROT ROT 1 SWAP START OVER + NEXT SWAP DROP }
  { DROP } IFTE NEXT ROT ROT DROP2 \>>
@ 180 bytes
@ 1000 random characters (from 256-char set)
@ 85K free memory at execution time, 85 seconds on GX with 2 cards.

This is a bit wasteful for sorting the letters of a short word of
capital letters only, since it goes through all 256 possible output
characters (taking 4.8 seconds on a word of one character only),
but it does of course get more efficient on longer random strings.

There is probably room for optimizing this a bit more,
but I've already used up my recreation time for the day :)

-----------------------------------------------------------
With best wishes from:   John H Meyers   <jhmeyers@mum.edu>


Final Thoughts

From: joehorn@jps.net
Subject: Re: Alphabetize a word

This mini-challenge turned out to be lots of fun!
But only two differing methodologies have been posted so far:

(a) Convert the string into a list of characters (or ASCII values),
then SORT the list, then convert the list back into a single string.

(b) Use one level of the stack to accumulate all the A's, another
level to accumulate the B's, and so on, until the string is all
used up, then concatenate the 26 stack levels into a single
string.  This is the faster method, because it avoids the SORT
command which is very slow on large lists.

Here's a third method that is kind of crazy but it's faster than
method (a)!

(c) Convert the string into an *array* of ASCII codes, then store it
into SigmaDAT, and let the BINS command tally the frequency of each
letter!  Unfortunately, BINS is no speed demon either.

For those of you who can read RPL, here's a working incarnation:

<< DUP SIZE -> s
  << 1 s
     START DUP NUM SWAP TAIL
     NEXT DROP s 1 2 ->LIST ->ARRY STOSigma
  >> 65 1 26 BINS DROP "" 1 26
  FOR j
    IF OVER j GET
    THEN 1 3 PICK j GET
      START j 64 + CHR +
      NEXT
    END
  NEXT SWAP DROP CLSigma 'SigmaPAR' PURGE
>>
BYTES: #2FC0h 214.0
Runtime on random 1000-char string: about 1.5 minutes.

Some other methodologies come to mind:

(d) Build the final output one character at a time, inserting
each new character into place using a binary search.

(e) Make 26 passes through the string, counting how many A's there
are, then how many B's, and so on.

(f) Sort the string "in place" by swapping characters. Any sorting
method could be used.

(g) Screw RPL and do it in assembly language, like God intended.

-Joe-
joehorn@jps.net


The Winner

From: joehorn@jps.net
Subject: Re: Alphabetize a word
Date: 10 Mar 1998 10:57:29 GMT

Robert Bellman's program is the current winner for size *
speed.  The best program that came out of the HP48 Programming
Class was similar to Robert's, but it was slowed down by using
HEAD and TAIL (instead of SUB, which is faster).

Way to go, Robert!

-Joe-
joehorn@jps.net