rexx

REXX codin with CSV input


Im new to coding with REXX and I need to make a program to find the Max, min and avg temperature for every month.

The input is Comma separated like below:

DAY/MONTH,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec      
1st,25.9,25.4,31.3,22.4,8.1,7.3,12.9,13.1,11.3,15.2,19.2,21    
2nd,27.2,22.3,18,14.6,10.2,10.9,10.9,13.5,15.9,24.9,26.2,17.2  
3rd,34.9,16.6,19.1,20.8,10.6,10.7,7,11.1,14.5,25.1,28.9,22.9   
4th,24.4,19.8,21.7,12.6,11.5,13,10.5,7.3,13.1,22.5,16.8,21.7   
5th,14.1,21.8,18.9,14.4,15.4,11.7,10.5,8.4,14,11.4,13.8,23.4
... etc

I need to create REXX code to find the the Max, Min and Mean temperature for each month and present it like below

User,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
Max,34.9,16.6,19.1,20.8,10.6,10.7,7,11.1,14.5,25.1,28.9,22.9   
Min,24.4,19.8,21.7,12.6,11.5,13,10.5,7.3,13.1,22.5,16.8,21.7   
Mean,14.1,21.8,18.9,14.4,15.4,11.7,10.5,8.4,14,11.4,13.8,23.4

Any help in creating the REXX code, or any literature/direction on it would be greatly appreciated.

So far my code is

/*REXX*/                                                                
/* TRACE ?I */                                                          
ADDRESS SYSCALL "READFILE /u/inputdata RECS."                      
                                                                        
IF RC <> 0 THEN DO                                                      
  SAY "ERROR READING FILE"                                              
  EXIT                                                                  
 END                                                                    
                                                                        
 FS=",";  MAXTEMP=""; MINTEMP=""; AVGTEMP=""                            
 DO I = 2 TO RECS.0                                                     
   PARSE VAR RECS.I DAY","JAN","FEB","MAR","APR","JUN","JUL","AUG","SEP","OCT","NOV,"DEC
     DO J = 2 TO RECS.I                                                 
           MAXTEMP = MAX(RECS.I)    /*Needs to add another VAR into Maxtemp*/
           MINTEMP = MIN(RECS.I)    /*same but Min                         */
           AVGTEMP = SUM(RECS.I)/COUNT(RECS.I)  /*Total/The amount of days*/ 
        END                                                                
    END                                                                    
 SAY user, JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
 SAY MAX, MAXTEMP        /*MAX for each month fill out*/               
 SAY MIN, MINTEMP        /*Min                        */               
 SAY MEAN, AVGTEMP       /*Avg                        */               
END                                                                    

Im trying to make a variable for MaxTemp, MinTemp and MeanTemp adding the months on as the loop goes.


Solution

  • Here is a possible implementation. It runs over each record as you did; this is the outer loop (loop variable ii). Then the current temperature for each month is

    1. compared to the current maximum for that month, and stored if greater
    2. compared to the current minimum for that month, and stored if lower
    3. added to the average sum-up field for the month

    This is the inner loop (lop variable jj). Note that the code inside this inner loop takes care not to process values for days beyond the maximum number of days per month.

    Since the year for the data doesn't seem to be known, the correct number of days for February cannot be calculated. You would need to add that, if the year is known.

    /*REXX*/                                                                
    /* TRACE ?I */
    address syscall "readfile /u/inputdata Recs."
    
    if RC <> 0 
    then do                                                      
        say "ERROR READING FILE"                                              
        exit 16                                                                  
        end                                                                    
                                                                            
    ifs = ","  /* Field separator for parsing input records */
    ofs = ","  /* field separator for writing output records */
    
    /* Initialize arrays to aggregate temperature data by month */
    MaxTemp. = 0
    MinTemp. = 99999
    AvgTemp. = 0                           
    
    /* Initialize array of number of days per month */
    /* We do not know the year, so we cannot calculate whether February has 28 or 29 days */
    DaysPerMonth.1  = 31
    DaysPerMonth.2  = 28 /* Need to be adjusted for leap years */
    DaysPerMonth.3  = 31
    DaysPerMonth.4  = 30
    DaysPerMonth.5  = 31
    DaysPerMonth.6  = 30
    DaysPerMonth.7  = 31
    DaysPerMonth.8  = 31
    DaysPerMonth.9  = 30
    DaysPerMonth.10 = 31
    DaysPerMonth.11 = 30
    DaysPerMonth.12 = 31
     
    /* Split (parse) each input record and fill the DayTemp array with daily temperatures by month */ 
    
    do ii = 2 to Recs.0
        parse var Recs.ii DayNum (ifs) DayTemp.1 (ifs) DayTemp.2  (ifs) DayTemp.3  (ifs) DayTemp.4  ,
                                 (ifs) DayTemp.5 (ifs) DayTemp.6  (ifs) DayTemp.7  (ifs) DayTemp.8  ,
                                 (ifs) DayTemp.9 (ifs) DayTemp.10 (ifs) DayTemp.11 (ifs) DayTemp.12 .
                    
        /* For each month, adjust min and max values, and sum up for building average later on */
        do jj =  1 to 12
    
            /* Don't process values for day numbers greater that number of days in month */
            if ( ii - 1 ) <= DaysPerMonth.jj
            then do
    
                if MaxTemp.jj < DayTemp.jj
                then MaxTemp.jj = DayTemp.jj
            
                if MinTemp.jj > DayTemp.jj
                then MinTemp.jj = DayTemp.jj
            
                AvgTemp.jj = AvgTemp.jj + DayTemp.jj
                              
                end /* if ( ii - 1 ) ... */
                
            end /* do jj = 1 to 12 */
                                
        end /* do ii = 1 to 12 */
        
    
    Heading = "User,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"
    Maxima  = "Max"
    Minima  = "Min"
    Means   = "Mean"
    
    /* Build the min, max and average records by appending value by value */
    
    do ii = 1 to 12
        Maxima = Maxima || ofs || format( MaxTemp.ii, 2, 1 )
        Minima = Minima || ofs || format( MinTemp.ii, 2, 1 )
        Means  = Means  || ofs || format( ( AvgTemp.ii / DaysPerMonth.ii ), 2, 1 )
        end 
      
    /* Write heading, min, max, and average records */  
    say Heading
    say Maxima
    say Minima
    say Means 
    

    Tip: Don't use single letter variable names, since you cannot search, or search-and-replace such names. I always use double letter variable names for loop variables, or temporary variables, such as ii, jj, kk, etc. These (most probably) never appear in the code in any other context, so searching for, and replacing can be easily done.