visual-foxpro

In Visual FoxPro, how does one incorporate a SUM REST command into a SCAN loop?


I am trying to complete a mortality table, using loops in Visual Foxpro. I have run into one difficulty where the math operation involves doing a sum of of all data in a column for the remaining rows - this needs to be incorporated into a loop. The strategy I thought would work, nesting a SUM REST function into the SCAN REST function, was not successful, and I haven't found a good alternative approach.

In FoxPro, I can successfully use the SCAN function as follows, say:

Go 1
Replace survivors WITH 1000000
SCATTER NAME oprev
SKIP
SCAN rest
  replace survivors WITH (1 - oprev.prob) * oprev.survivors
  SCATTER NAME oprev
ENDSCAN

(to take the mortality rates in a table and use it to compute number of survivors at each age)

Or, say:

Replace Yearslived WITH 0 
SCATTER NAME oprev1
SKIP
SCAN rest
   replace Yearslived WITH (oprev1.survivors + survivors) * 0.5
   SCATTER NAME oprev1
ENDSCAN

In order to complete a mortality table I want to use the Yearslived and survivors data (which were produced using the SCANs above) to get life expectancy data as follows. Say we have the simplified table:

SURVIVORS YEARSLIVED LIFEEXP
100       0            ?
80        90           ?
60        70           ?
40        50           ?
20        30           ?
0         10           ?

Then each LIFEEXP record should be the sum of the remaining YEARSLIVED records divided by the corresponding Survivors record, i.e:

LIFEEXP (1) = (90+70+50+30+10)/100
LIFEEXP (2) = (70+50+30+10)/80

...and so on.

I attempted to do this with a similar SCAN approach - see below:

Go 1
SCATTER NAME Oprev2
SCAN rest
   replace lifeexp WITH ((SUM yearslived Rest) - oprev2.yearslived) / oprev2.survivors
   SCATTER NAME oprev2
ENDSCAN

But here I get the error message "Function name is missing)." Help tells me this is probably because the function contains too many arguments.

So I then also tried to break things down and first use SCAN just to get all of my SUM REST data, as follows:

SCAN rest
  SUM yearslived REST
END SCAN

... in the hope that I could get this data, define it as a variable, and create a simpler SCAN function above. However, I seem to be doing something wrong here as well, as instead of getting all necessary sums (first the sum of rows 2 to end, then 3 to end, etc.), I only get one sum, of all the yearslived data. In other words, using the sample data, I am given just 250, instead of the list 250, 160, 90, 40, 10.

What am I doing wrong? And more generally, how can I create a loop in Foxpro that includes a function where you Sum up all remaining data in a specific column over and over again (first 2nd through last record, then 3rd through last record, and so on)?

Any help will be much appreciated!

TM


Solution

  • Well you are really hiding the important detail, your table's structure, sample data and desired output. Then it is mostly guess work which have a high chance of to be true.

    You seem to be trying to do something like this:

    Create Cursor Mortality (Survivors i, YearsLived i, LifeExp b)
    Local ix, oprev1
    For ix=100 To 0 Step -20
        Insert Into Mortality (Survivors, YearsLived) Values (m.ix,0)
    Endfor
    Locate
    Survivors = Mortality.Survivors
    Skip
    Scan Rest
        Replace YearsLived With (m.Survivors + Mortality.Survivors) * 0.5
        Survivors = Mortality.Survivors
    Endscan
    

    *** Here is the part that deals with your sum problem

    Local nRecNo, nSum
    Scan
        * Save current recnord number
        nRecNo = Recno()
        Skip
    
        * Sum REST after skipping to next row
        Sum YearsLived Rest To nSum
        
        * Position back to row where we started
        Go m.nRecNo
        
        * Do the replacement
        Replace LifeExp With Iif(Survivors=0,0,m.nSum/Survivors)
        * ENDSCAN would implicitly move to next record
    Endscan
    * We are done. Go first record and browse
    Locate
    Browse
    

    While there are N ways to do this in VFP, this is one xbase approach to do that and relatively simple to understand IMHO.

    Where did you go wrong?

    Well, you tried to use SUM as if it were a function, but it is a command. There is SUM() function for SQL as an aggregate function but here you are using the xBase command SUM.

    EDIT: And BTW in this code:

    SCAN rest
      SUM yearslived REST
    ENDSCAN
    

    What you are doing is, starting a SCAN with a scope of REST, in loop you are using another scoped command

    SUM yearslived REST
    

    This effectively does the summing on the REST of records and places the record pointer to bottom. Endscan further advances it to eof(). Thus it only works for the first record.