Make Mine MAPPER #38 -------------------- by Rob Haeuser How Do I Use Thee? Let Me COUNT The Ways... ----------------------------------------------------------------- Ladies and Gentlemen! Step right up! That's it, crowd around. You over there, the guy with the red frizzy horizontal hair. Come on over. Bet those feet could give Flipper a run for his money! Wanna see one of the latest and greatest functions on earth? Not so fast, kid. Quit shoving. So, what's yer name, sonny? Eh? @REC? What the heck kind'a name is that? Norwegian? Bet you're the guy who came up with that wacky invention for making hammers from lilies. What I want to know is: How'd you ever convince 'em to name a whole city for such a stupid idea? Obviously too much snow can numb the brain. Sorry, @REC, but you'll just have to wait your turn. We're here today to see a couple of neat tricks from COUNT, one of the most versatile functions to hit the big-top since CALamity Jane came riding through bare-back with both barrels blazing. Hey! Now you just go rinse your mind out with soap right now! I meant that the horse had no saddle and her guns were firing. Sheesh!! Now, on with the show. First, we have an example of COUNT saving the logic-loop day. The problem is this: We have a bunch of data that needs to be reformatted for COBOL. There are three different formats required, depending on a single character within the key. The initial version of the run read a record and branched to a label to output a line (see Figure 1). Pretty straight forward, simple, and to the point. But the LLP (Logic Lines Processed) limit had to be set very high, and it seemed like there could be a better way. Enter COUNT, stage left (see Figure 2). ------------------------------------------------------------------ Figure 1 -------- *================================================================== @LDV V1I6=5 . <-load the line counter variable @BRK ... do something to get a bunch of data ... SRH, etc. @SOR,-0 '' 2-10 ~,1 RNM -1 . <- sort it and save as -1 @5:INC V1 RDL,-1,V1,20 1-80 V80 . <- read next rec @IF V80(7-1) = 0,2,4,(12),1,3,5,(14) ;. <- branch based on the key 1 V80(1-10) V80(11-30) V80(31-10) @GTO 5 . @12 . 2 V80(1-20) V80(31-10) V80(21-10) @GTO 5 . @14 . 3 V80(1-15) V80(21-10) V80(31-10) V80(16-5) @GTO 5 . @20:BRK FIL,-0... GTO END . <- create a disk file and go to sleep ------------------------------------------------------------------- ------------------------------------------------------------------- Figure 2 -------- *================================================================== @LDV V1I6=5,V11I1,V12I6,V13I6 . <-load a bunch of variables @BRK ... do something to get a bunch of data ... SRH, etc. @SOR,-0 '' 7-1 ~,1 RNM -1 . <- sort it just on partial key @CNT,-1 AP 7-1,20-6,28-6 ~,1,=,:L RNM -2 . <- ta da!!! @5:INC V1 RDL,-2,V1,20 2-1,4-6,11-6 V11,V13,V12 . <- get next group @IF V11 = 0,2,4,(12),1,3,5,(14) ;. <- branch based on the key @RDC,-1,V12,V13 1-80 V80 . 1 V80(1-10) V80(11-30) V80(31-10) @GTO 5 . @12:RDC,-1,V12,V13 1-80 V80 . 2 V80(1-20) V80(31-10) V80(21-10) @GTO 5 . @14:RDC,-1,V12,V13 1-80 V80 . 3 V80(1-15) V80(21-10) V80(31-10) V80(16-5) @GTO 5 . @20:BRK FIL,-0... GTO END . <- create a disk file and go to sleep ------------------------------------------------------------------- The two versions seem very much alike on the surface. However, the first reads each individual record, while the second reads entire blocks of records. The trick, of course, is the @CNT that precedes the reformatting logic. We are sorting the data just on the single digit that determines the format type. Then, we COUNT the number of occurrences of each single digit (=), while loading the starting line number of the occurrences (:L). These two values, the starting line number and the number of lines, are then used by the @RDC (Read Continuous) function. Next, we read through the COUNT result (-2), looping to the appropriate @RDC based on the same logic used in Figure 1. Now, rather than reading individual records, we are reading entire blocks at a time. Needless to say, the LLPs dropped to near zero, while the IO required was roughly the same, even with a COUNT thrown onto the pile. Obviously much more efficient. Kudos to David Riskind of the Radian Corporation for this innovative use of a new, and, quite frankly, rather complex function. And for trying something different, rather than simply bumping up the LLP limit until the damn thing ran. So, Dave, is my $10 in the mail? The next example is taken from GURU, a set of run utilities that I authored and am now marketing. One of the utilities creates a drawer permission list, showing all drawers a user can access. Additionally, if you are a coordinator, you can request a list of all users in a particular security report and group. Traditionally, the compilation of the list of all users would be coded something like this: Set up a report variable, search each user department report independently, tot in the department number, reformat into the output area, loop to the next report until all are searched, then break, sort the result by user-id and department and display the result. Tedious, but effective. Now I want all you @CAL nuts to back off right now! I know that CAL could substitute for the search and tot, but that just ain't good enough. I would still have to loop through each report individually. Boring. Figure 3 demonstrates how a single COUNT can eliminate major portions of the logic. First, a screen has been displayed to solicit a security report and group, contained in V3 and V4 respectively. We are going to use the scaling option in COUNT to, in essence, search for the two values. ------------------------------------------------------------------- Figure 3 -------- *================================================================== @. display a screen to solicit a security report and group @ART V3-.5;V3+.5;V4-.5;V4+.5 V11F5.1,V12F5.1,V13F4.1,V14F4.1 . @CNT,USRDRW$ PS1(1/V11/V12)S2(1/V13/V14)\ 2-11,14-4,21-4,99-13,113-14,134-4,139-3 ~,A,3R,4L,B,C,1,2 . @SOR,-0 '' 11-4,21-11 ~,2,1 BRK . . All Users in Security Report V3, Group V4 * * User-id Dpt# User Name Empl#/Phone *===========.====.=============.==============. @RDC,-0,8 11-4,21-11,33-13,47-14 V15H,V16H,V17H,V18H . ~V16 V15 V17 V18 @BRK DSX,-0,,,,,H . ------------------------------------------------------------------- The @ART statement creates 4 variables, V11 through V14. They represent the minimum and maximum values for the report and group, and are offset by .5 to create a scaling range of 1. The @CNT uses the "P" option to remove all non-referenced fields. The "S1" is the scaling option for the first key (the report filed in 134-4). The "1" in the parenthesis represents the scaling factor, while V11 and V12 represent the min and max values. The "S2" is doing the same thing for the secondary key (the group filed in 139-3). Note the parameters being used. The "A", "B", and "C" tells COUNT to simply include these fields (User-id, User name, and Empl#/Phone). The "3R" says this is the third key field and is to be loaded with the report, which is the department number. The "4L" is a bit sneaky. It tells COUNT that it is the 4th key field, and is to be loaded with the line number of the "find". This is required simply because COUNT automatically collapses on the key(s), and without it, I would only get 1 record per department. Got it? Good. So the COUNT screams through the entire drawer, only pulling records within the two scales, loading the department number, and retaining a few fields for display. Finally, we sort the result and reformat with a read-continuous (RDC) to make it pretty. This one COUNT substituted for numerous searches and tots. And, of course, was much faster in the process. All I can say is: let's hope Unisys will still support all the other functions, even if COUNT can do it all. I still enjoy a simple-minded search once in a while. And, hey, @REC, go get some sun. You're as pale as a bozo. ----------------------------------------------------------------- Rob Haeuser has more than 19 years of Data Processing experience. He was MAPPER Coordinator and Run Designer for the Texas Department of Human Services for ten years, and is now an independent contractor working in the Austin area. He also authored and is marketing a set of MAPPER run utilities called GURU. Covering MAPPER topics ranging from technical to tacky, his never-ending quest is for truth, justice, and the MAPPER way. Please direct all communications to: GURU Enterprises Attn Rob Haeuser 3212 Great Valley Drive Cedar Park, Tx. 78613 or call: 512-335-3862 (fax) / 512-331-0498 (voice)