VISUAL BASIC -- The Beginnings
Here we revisit the Aquarium membership problem with a more compact and "elegant" solution to the problem. In several parts of our original solution, we needed to re-initialize the MembershipCount by MembershipType ARRAY .. and we also wrote out the compiled array in a two or more places.
In this solution, we employ the powerful feature of all modern programming languages -- The SUBROUTINE. Subroutines or sub-programs are smaller, separate, mini-programs which do special tasks. Often these tasks are needed in different parts of the MAIN PROGRAM or even in different programs (re-usable code).
Visual Basic will rely entirely on subroutines -- we will only write subroutines, the "main program" is generated by the "visual" part -- the Graphical User Interface we build with the visual tools. Actual "work" is done in subroutines .. the parts that we write.
We need to look more carefully at our VARIABLES and decide which will be "local" to a subroutine and which need to be "global" or SHARED. SHARED variables (declared in the DIM statement) will have their current values known to all subroutines at the same time. Local variables are used within subroutines and do not affect other parts of the program.
Local variables are sometimes
"passed" to another subroutine to be used by that program. This is
similar to the "functions" we have used already such as:
ITYPE = INT(MTYPE) .. where INT( ** ) is the function [which returns the integer value of a real number, either single or double] and MTYPE is the "argument" or variable passed to the function.In this version of our program, we will use both SHARED variables and local variables passed to the subroutine.
Notice that the Main Program is first (in VB, we never see the "main program per se") and all the SUBroutines follow. We can edit them without changing anything in the Main Program -- VB is based on this principle, you edit your SUBroutines and leave the main program alone.
I think the "logic" of solving the membership types by zipcode problem described last week will be clearer with the use of subroutines -- you can see the program in its logical whole easier as much of the "work" is done in the subroutines.
STUDY the program and see if you understand the ways it works. The new program has been added to the ZIP and ready for download.
'-------------------------------------------------------
DECLARE SUB
ADDMEMS (MTEMP AS SINGLE, NTEMP AS INTEGER)
DECLARE SUB
INITNEW ()
DECLARE SUB
MEMDUMP ()
OPTION BASE 1
DIM SHARED
MEMTYP(5) AS SINGLE 'ARRAY OF MEMBERSHIP TYPE COUNTS
BY ZIPCODE
DIM SHARED
ZIPCODE AS STRING 'ZIPCODE NUMBER AS A CHARACTER STRING
'---------------------------------------------------------
DIM MTEMP
AS SINGLE 'TEMPORARY MEMBERSHIP TYPE
DIM ZTEMP
AS STRING 'TEMPORARY ZIPCODE
DIM NTEMP
AS INTEGER 'TEMPORARY MEMBERSHIP COUNT BY TYPE
DIM FIRST
AS INTEGER 'CONTROL OF OUTPUT VARIABLE
' OPEN DISKFILES
OPEN "ZIP_RAW.TXT"
FOR INPUT AS #1
OPEN "Z_TEMP.TXT"
FOR OUTPUT AS #2
CLS
'CLEAR THE SCREEN
'-------------------------------------------------
' Initialize
ZipCode Value and MemTyp Array Prior to Input
ZIPCODE = "00000"
FIRST = 1
CALL INITNEW
' BEGIN DATA
INPUT FROM DISKFILE IN ORIGINAL FORMAT
'
ZIPCODE, MemberType, MemberCount
WHILE NOT EOF(1)
INPUT
#1, ZTEMP, MTEMP, NTEMP
'PRINT ZTEMP, MTEMP, NTEMP 'DEBUG TEMP PRINT --DELETE LATER
IF ZTEMP <> ZIPCODE THEN 'NEW ZIP CODE
IF FIRST THEN 'FIRST TIME THRU THE PROCESS -- SAVE INFO ONLY
ZIPCODE = ZTEMP
CALL ADDMEMS(MTEMP, NTEMP)
FIRST = 0
ELSE 'NEW ZIPCODE ENCOUNTERED, DUMP OLD ZIP MEMBERSHIP INFO
CALL MEMDUMP
ZIPCODE = ZTEMP
CALL INITNEW
CALL ADDMEMS(MTEMP, NTEMP)
END IF
ELSE ' SAME ZIP AS LAST RECORD, ADD INFOMATION TO MEMBERSHIP ARRAY
CALL ADDMEMS(MTEMP, NTEMP)
END IF
' INPUT KY$ ' DEBUG KEY INPUT -- DELETE LATER
WEND
'END OF INPUT FILE ENCOUNTERED --
CALL MEMDUMP ' WRITE LAST ZIPCODE'S INFO TO FILE
CLOSE
'ALL FILES
END
SUB ADDMEMS
(MTEMP AS SINGLE, NTEMP AS INTEGER)
DIM I, J
AS INTEGER
I =
INT(MTEMP)
MEMTYP(I)
= NTEMP
END SUB
SUB INITNEW
DIM
I AS INTEGER
FOR I = 1 TO 5
MEMTYP(I) = 0
NEXT I
END SUB
SUB MEMDUMP
PRINT ZIPCODE, MEMTYP(1); MEMTYP(2); MEMTYP(3); MEMTYP(4); MEMTYP(5)
'WRITE #2, ZIPCODE, MEMTYP(1), MEMTYP(2), MEMTYP(3), MEMTYP(4), MEMTYP(5)
END SUB
Problem #3: -- REAL WORK
Here is a real problem we encountered last week as part of the Austria-Exchange project with the Aquarium. We needed to get counts of Membership Types (collapsed into 5 classes) into a Single Table with ZipCode as the Primary Key in order to make a Pie-Chart Map of Membership Types by ZipCode area.
Woody and Suzanne were able to
summarize the membership types by ZipCode, but only to the extent that
an ACCESS (database) table was produced that logically looked like this:
ZIPCODE | MEMCLASS | SUMNo one could figure out how to get ACCESS or ARCVIEW to reformat the table into a single row (record) with Zipcode and then the numbers of members in EACH CLASS. So we exported the table into Comma-Delimited ASCII (text).
A portion of the "raw data" looks like this:
"90071",1.00,1
"90071",3.00,1
"90075",2.00,1
"90075",3.00,1
"90077",1.00,3
"90077",2.00,5
"90077",3.00,20
"90077",4.00,5
"90077",5.00,6
"90081",4.00,2
"90086",2.00,1
"90086",4.00,1
"90089",4.00,1
"90201",1.00,1
"90201",2.00,3
"90201",3.00,16
"90201",4.00,2
"90202",3.00,1
"90209",4.00,1
"90210",1.00,8
"90210",2.00,2
"90210",3.00,25
"90210",4.00,7
"90210",5.00,3
Getting the data into an
text file allowed me to write a short program to read the data and output
into the desired format, which logically looks like this:
ZIPCODE | TYPE1 | TYPE2 | TYPE3 | TYPE4 | TYPE5A portion of the output, corresponding to the data sample above, is show here:
"90071",1,0,1,0,0The complete data file (exported from ACCESS) [Z_mc_cnt.txt], the "edited Input File" [z_in.txt] cleaned up and ready to run, and the BASIC program [zip_bas.txt] are all found in this file zipcodes.zip -- available for your download.
"90075",0,1,1,0,0
"90077",3,5,20,5,6
"90081",0,0,0,2,0
"90086",0,1,0,1,0
"90089",0,0,0,1,0
"90201",1,3,16,2,0
"90202",0,0,1,0,0
"90209",0,0,0,1,0
"90210",8,2,25,7,3
The BASIC program contains a number of "tricks" which make the conversion pretty simple -- once you understand the underlying logic. STUDY this program. Not for its elegance, but for an example of how to work through the knarly logic necessary to solve the problem.
Try writing your own version.
Viele Gluck.
#2
DIM NUMREC AS INTEGER
OPEN "CITIES.TXT" FOR INPUT AS #1
OPEN "CITYXY.TXT" FOR OUTPUT AS #2
OPEN "CITYDAT.TXT" FOR OUTPUT AS #3
NUMREC = 0
CLS
WRITE #2, "ID" , "LON", "LAT" ' Header Record indicates data column
names for Arcview
WRITE #3, "ID", "CITY", "POP", "SPKSPAN" 'Header Record for the
Attribute File
WHILE NOT EOF(1) ' LOOP UNTIL END OF FILE ON INPUT -- NO MORE
DATA
PRINT CITY; LON; LAT; POP; SPKSPAN 'PRINT TO SCREEN
WRITE #2, NUMREC, LON, LAT ' write X-Y coords to GeoFile
WRITE #3, NUMREC, CITY, POP, SPKSPAN ' write Attributes to Datafile