[comp.databases] Arrays in dBASE

steve@violet.berkeley.edu (Steve Goldfield) (01/29/88)

Someone commented recently on the absence of arrays in dBASE.
When I first bought it in 1983, I considered that a big drawback,
especially since I was limited to only 64 variables in II. I
managed to make pseudo arrays by using string addition to add the
indices to the array name using macros. More recently, however, I
realized there was a neater solution. An array is a sort of
table, so it can be stored in a database with a single (or for
that matter multidimensional arrays can be handled, too) field.
In a program I wrote recently in McMax (the Macintosh version of
dBASE III), I needed an array and put it in such a database which
I delete and pack as soon as I'm done with it. Clearly, it is
quicker to use an array stored in memory than a database stored
on disk, but in dBASE it is much easier in terms of programming
to use the database approach.

Steve Goldfield

mjr@well.UUCP (Matthew Rapaport) (02/03/88)

In article <6760@agate.BERKELEY.EDU> steve@violet.berkeley.edu (Steve Goldfield) writes:
> ...a neater solution. An array is a sort of
>table, so it can be stored in a database with a single (or for
>that matter multidimensional arrays can be handled, too) field.
>
Yes, you can always trade memory structures for file structures if your
file handling system is up to it (and d:Base's is), but what you really
loose in having to do this is performance!

steve@violet.berkeley.edu (Steve Goldfield;232HMB;3-6292;;MF62) (02/04/88)

In article <5134@well.UUCP> mjr@well.UUCP (Matthew Rapaport) writes:
>In article <6760@agate.BERKELEY.EDU> steve@violet.berkeley.edu (Steve Goldfield) writes:
>> ...a neater solution. An array is a sort of
>>table, so it can be stored in a database with a single (or for
>>that matter multidimensional arrays can be handled, too) field.
>>
>Yes, you can always trade memory structures for file structures if your
>file handling system is up to it (and d:Base's is), but what you really
>loose in having to do this is performance!

I agree and made this point in the original post. But all of the
arrays I've written in dBASE, for instance to contain Boolean
statements defining zipcode ranges, have been very small and when
I put them into a database on the Mac II I am currently using, I
can't see any degradation in performance. If you need very large
arrays, I doubt that dBASE would be the language of choice not
only for storage but for manipulation flexibility and control.

As an example, I'll post my dBASE search and replace program,

* SRCHFULL.CMD VERSION 3  SAG 1/11/85
* THIS FUNCTION SEARCHES FOR AND REPLACES CHARACTERS OR STRINGS IN FIELDS
* UNLIKE SRCHREPL IT ALLOWS SIMULTANEOUSLY REPLACEMENT OF UP TO NINE
* CHARACTERS AND FIELDS AT A TIME
* THE ADVANTAGE OF THIS METHOD IS SPEED.  THE LIMITING FACTOR IS
* THE TIME IT TAKES TO ACCESS A RECORD.  IN THIS WAY, ONE ACCESS
* ALLOWS MULTIPLE SEARCH AND REPLACE OPERATIONS.
* YOU CAN KEEP GOING WITH NEW FILES UNTIL YOU SAY STOP
* 1/11/85 MODIFIED TO USE GET AND READ WHERE APPROPRIATE
* 12/20/85 MODIFIED TO DELETE CHARACTERS BY USING ` AS REPLACE CHARACTER
* 12/3/87 MODIFIED TO REPLACE STRINGS AS WELL AS CHARACTERS
CLEAR
STORE T TO FLOOKING
* MAIN DO LOOP 1
DO WHILE FLOOKING
SET TALK OFF
CLEAR
* COULD ASK FOR OR SET DEFAULT DRIVE WITH DBASE FILES
* SET DEFAULT TO K
  LIST FILES
  ACCEPT 'TYPE THE NAME OF THE FILE' TO FILENAME
ERASE
STORE 1 TO FRECNUM
@ 10,5 SAY "NUMBER OF FIRST RECORD TO SEARCH?" GET FRECNUM PICTURE '9999'
READ
  USE &FILENAME
* SHOW STRUCTURE TO USER TO HELP PICK FIELD NAMES
  LIST STRUCTURE
  STORE T TO LOOKINGF
* DO LOOP 2 FOR EACH FILE
    DO WHILE LOOKINGF
      STORE 0 TO FCOUNT
      STORE T TO FSETTING
* DO LOOP 3 TO STORE FIELD NAMES
      DO WHILE FCOUNT<10 .AND. FSETTING
 STORE FCOUNT + 1 TO FCOUNT
* NEXT STATEMENT GENERATES AN ARRAY
* COULD WRITE AN ARRAY COMMAND TO GENERATE ARRAY NAMES
* FOR FILLING OR ACCESSING
 STORE 'FLNAME' + STR(FCOUNT,1,0) TO FIELDS
 ACCEPT 'TYPE FIELD NAME' TO &FIELDS
* COULD INSERT A CHECK FOR PROPER FIELD NAME HERE
STORE " " TO FSTOP
@ 23,40 SAY 'MORE FIELDS? Y/N?' GET FSTOP PICTURE 'A'
READ
 IF !(FSTOP)='N'
   STORE F TO FSETTING
 ENDIF
* END 3
      ENDDO
      STORE 0 TO CCOUNT
      STORE T TO CSETTING
CLEAR
* DO LOOP 4 TO STORE CHARACTERS OR STRINGS
@ 22,5 SAY 'TO DELETE A CHARACTER OR STRING, TYPE ` AS REPLACE CHARACTER'
 STORE 2 TO LINE
      DO WHILE CCOUNT<10 .AND. CSETTING
 STORE CCOUNT + 1 TO CCOUNT
* NEXT TWO STATEMENTS GENERATE ARRAYS
 STORE 'OCHAR' + STR(CCOUNT,1,0) TO OCHARS
 STORE 'NCHAR' + STR(CCOUNT,1,0) TO NCHARS
STORE ' ' TO &OCHARS
STORE ' ' TO &NCHARS
@ LINE,5 SAY 'TYPE SEARCH CHARACTER OR STRING' GET &OCHARS
READ
@ LINE+1,5 SAY 'TYPE REPLACE CHARACTER OR STRING' GET &NCHARS
READ
STORE LINE+2 TO LINE
STORE ' ' TO CSTOP
@ 20,5 SAY 'MORE CHARACTERS OR STRINGS? Y/N?' GET CSTOP PICTURE 'A'
READ
 IF !(CSTOP)='N'
   STORE F TO CSETTING
 ENDIF
* END 4
      ENDDO
STORE ' ' TO BL
CLEAR
@ 10,20 SAY 'PLEASE WAIT ... SEARCHING FILE'
@ 12,30 SAY "&FILENAME"
SET TALK OFF
GOTO FRECNUM
* DO LOOP 5 TO BEGIN SEARCH/REPLACE
@ 20,20 SAY "Now searching record number"
DO WHILE .NOT. EOF
  @ 22,30 SAY #
  STORE 0 TO COUNTF
* DO LOOP 6 TO SEARCH EACH FIELD
  DO WHILE COUNTF<FCOUNT
    STORE COUNTF + 1 TO COUNTF
    STORE 'FLNAME' + STR(COUNTF,1,0) TO FLDNAME
* THIS IS A KEY STATEMENT--THE DOUBLE MACRO GETS THE
* ACTUAL FIELD NAME STORED IN THE APPROPRIATE ARRAY POSITION
    STORE &&FLDNAME TO FSTRING
    STORE 0 TO COUNTC
    STORE 0 TO HIT
* DO LOOP 7 TO REPLACE EACH CHARACTER OR STRING
    DO WHILE COUNTC<CCOUNT
      STORE COUNTC + 1 TO COUNTC
      STORE 'OCHAR' + STR(COUNTC,1,0) TO OCHARM
      STORE 'NCHAR' + STR(COUNTC,1,0) TO NCHARM
      STORE &OCHARM TO OCHAR
      STORE &NCHARM TO NCHAR
      STORE 1 TO CNUM
* DO LOOP 8 TO SEARCH FOR ALL HITS
* CNUM IS NONZERO WHEN THERE IS A HIT
* THE LOOP WHICH FOLLOWS ALLOWS FOR MULTIPLE OCCURRENCES
      DO WHILE CNUM # 0
        DO C:SEARCH
* END LOOP 8
      ENDDO
* END LOOP 7
    ENDDO
* COMMAND SEARCH GENERATES A REPLACEMENT FSTRING
* THE REPLACEMENT IS MADE IF THERE ARE ANY HITS
    IF HIT>0
      REPLACE &&FLDNAME WITH FSTRING
    ENDIF
* END LOOP 6
  ENDDO
  SKIP
* END LOOP 5
ENDDO
* END LOOP 2
  STORE F TO LOOKINGF
ENDDO
  USE
  ERASE
  STORE ' ' TO FINISH
  @ 10,5 SAY 'FINISHED? Y/N?' GET FINISH PICTURE 'A'
  READ
  IF !(FINISH)='Y'
    STORE F TO FLOOKING
  ENDIF
* END LOOP 1
ENDDO
CLEAR
RETURN

* SEARCH.CMD  VERSION 1  SAG  3/24/83
* THIS FUNCTION FINDS AND REPLACES CHARACTERS OR STRINGS
* PREPARE IN CASE CHARACTER IS FIRST OR LAST OR ONLY CHARACTER IN STRING
* 12/3/87 MODIFIED TO HANDLE STRINGS AS WELL AS CHARACTERS
STORE ' ' TO FPART
STORE ' ' TO LPART
STORE LEN(FSTRING) TO LENFS
* LOOK FOR THE OLD CHARACTER OR STRING IN THE STRING
* IF IT'S THERE, CNUM IS THE LOCATION OF THE FIRST OCCURRENCE.
* IF NOT, CNUM IS ZERO.
STORE @(OCHAR,FSTRING) TO CNUM
STORE LEN(OCHAR) TO LENO
IF CNUM > 0
* SETTING HIT TO 1 MEANS A REPLACEMENT WILL BE NECESSARY LATER
  STORE 1 TO HIT
* MCNUM IS THE LENGTH OF THE STRING PRECEDING THE CHARACTER
  STORE CNUM - 1 TO MCNUM
* SAVE PRECEDING CHARACTERS IF CHARACTER ISN'T FIRST CHARACTER
  IF MCNUM > 0
    STORE $(FSTRING,1,MCNUM) TO FPART
  ENDIF
* SAVE FOLLOWING CHARACTERS IF CHARACTER ISN'T LAST CHARACTER
  IF CNUM < LENFS
* ACNUM IS THE FIRST CHARACTER AFTER THE OCCURRENCE 
    STORE CNUM + LENO TO ACNUM
* LNUM IS THE LENGTH OF THE SECOND PART OF THE STRING
    STORE LENFS - CNUM - LENO + 1 TO LNUM
    STORE $(FSTRING,ACNUM,LNUM) TO LPART
  ENDIF
* REBUILD THE STRING WITH THE NEW CHARACTER IN PLACE
* IF FPART IS BLANK, THE - REMOVES IT
  IF LENFS > 1
    IF .NOT. NCHAR$'`'
      STORE TRIM(TRIM(FPART - NCHAR) + LPART) TO FSTRING
    ELSE 
      STORE TRIM(FPART - LPART) TO FSTRING
    ENDIF NCHAR#'
  ELSE
    STORE NCHAR TO FSTRING
  ENDIF
ENDIF
RELEASE FPART,LPART,MCNUM,LENFS,ACNUM,LENO
RETURN

If you examine the programming necessary to get data into arrays
like the above and then to get it out, I suspect you would find
that putting the arguments in a database (although it would mean
some loss of generality in the length of possible search and
replace strings) would save more performance than lost.