Array name in a variable (sorting an array)

May 20, 2008
9,839
69
Syracuse, NY, USA
Using an array whose name is in a variable is tricky (at least I have a hard time remembering how to do it). Here's how.

Code:
v:\> setarray b[2] & set b[0]=1 & set b[1]=0

v:\> set aname=b

v:\> echo %[aname[0]] %[aname[1]]
1 0
That said, here's a BTM to sort a 1-D array by name. I tried to make it robust but I'm sure it can be broken (oddball characters will surely do it). Hopefully, Rex will add a SORTARRAY as suggested.

Code:
:: SORTARRAY.BTM
setlocal
if %# lt 1 (echoerr Syntax: SORTARRAY array_name [/N(umeric)] [/R(everse)] & quit)
set aname=%1
if %@arrayinfo[%aname,0] NE 1 (echoerr array does not exist or is not 1-dimensional & quit)
set dim=%@arrayinfo[%aname,1]
set last=%@dec[%dim]

shift
set numeric=0
set op=LT

do while "%1" == "/N" .or. "%1" == "/R"
    if "%1" == "/N" (set numeric=1) else (set op=GT)
    shift
enddo

iff %numeric == 1 then
    do i=0 to %last
        if "%[aname[%i]]]" == "" (echoerr numbers cannot be empty & quit)
    enddo
endiff

do i=0 to %@dec[%last]
    do j=%@inc[%i] to %last
        iff %numeric == 1 then
            if %[aname[%j]] %op %[aname[%i]] gosub switch
        else
            if "%[aname[%j]]" %op "%[aname[%i]]" gosub switch
        endiff
    enddo
enddo
quit

:switch
set uty=%[aname[%i]]
set %aname[%i]=%[aname[%j]]
set %aname[%j]=%uty
return
Some examples:
Code:
v:\> setarray b[5] & do i=0 to 4 (set b[%i]=%@mrand[1,10])

v:\> do i=0 to 4 ( echo %b[%i] )
9
10
9
6
8

v:\> sortarray.btm b /n

v:\> do i=0 to 4 ( echo %b[%i] )
6
8
9
9
10

v:\> sortarray.btm b /n /r

v:\> do i=0 to 4 ( echo %b[%i] )
10
9
9
8
6

v:\> unsetarray b

v:\> setarray b[3] & set b[0]=dog & set b[1]=cat & set b[2]=hamster

v:\> echo %b[0] %b[1] %b[2]
dog cat hamster

v:\> sortarray.btm b

v:\> echo %b[0] %b[1] %b[2]
cat dog hamster

v:\> sortarray.btm b /r

v:\> echo %b[0] %b[1] %b[2]
hamster dog cat
 
Last edited:
May 20, 2008
9,839
69
Syracuse, NY, USA
Ha! That doesn't seem to be the way to sort a big array. It takes SORTARRAY.BTM 8 minutes to sort a 1x1000 array! I can dump that array to a file, use Gnu SORT on the file, and load the file back into the array in 6 seconds!
 
May 20, 2008
9,839
69
Syracuse, NY, USA
With some (rather obvious?) tweaks, I got that 8 minutes down to 2 minutes 20 seconds.

The tweaks were:

1. have entirely separate routines for numeric and string sorts (so %numeric is tested only once).
2. don't swap a and a[j] every time a[j] is better; instead, wait until the best j is found, then swap
3. do (set lasti=%@dec[%last]; for i=0 to %lasti ...) instead of (do i=0 to %@dec[%last] ...) to reduce evaluating @DEC (to once)
4. do (unset *) (in setlocal, of course) ... makes finding environment variables quicker
5. get rid of the subroutine

The BTM now looks like this.

Code:
:: SORTARRAY.BTM
setlocal
unset *
if %# lt 1 (echoerr Syntax: SORTARRAY array_name [/N(umeric)] [/R(everse)] & quit)
set aname=%1
if %@arrayinfo[%aname,0] NE 1 (echoerr array does not exist or is not 1-dimensional & quit)
set dim=%@arrayinfo[%aname,1]
set last=%@dec[%dim]

shift
set numeric=0
set op=LT

do while "%1" == "/N" .or. "%1" == "/R"
    if "%1" == "/N" (set numeric=1) else (set op=GT)
    shift
enddo

iff %numeric == 1 then
    do i=0 to %last
        if "%[aname[%i]]]" == "" (echoerr numbers cannot be empty & quit)
    enddo
endiff

set lasti=%@dec[%last]

iff %numeric == 1 then
    do i=0 to %lasti
        set ibetter=%i
        do j=%@inc[%i] to %last
            if %[aname[%j]] %op %[aname[%ibetter]] set ibetter=%j
        enddo
        set uty=%[aname[%i]] & set %aname[%i]=%[aname[%ibetter]] & set %aname[%ibetter]=%uty
    enddo
else
    do i=0 to %lasti
        set ibetter=%i
        do j=%@inc[%i] to %last
            if "%[aname[%j]]" %op "%[aname[%ibetter]]" set ibetter=%j
        enddo
        set uty=%[aname[%i]] & set %aname[%i]=%[aname[%ibetter]] & set %aname[%ibetter]=%uty
    enddo
endiff