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.