locate function fails

Discussions about CSEntry
Forum rules
New release: CSPro 8.0
Post Reply
groverlynn
Posts: 6
Joined: March 23rd, 2018, 10:14 pm

locate function fails

Post by groverlynn »

I want to write a logic to locate the last case in the data, case ID prefix being GEO_CODE and LISTER. Here is my code

Code: Select all

if locate(TPL_HH_DICT, <, GEO_CODE+LISTER) then
	loadcase(TPL_HH_DICT);
	HH_NO = HH + 1;
else
	HH_NO = 99; //I intend to use HH_NO = 1, but just to see if the locate works, I use 99 here
endif;
However, this always gives me HH_NO = 99 (unable to locate any case).
But when I change "<" into ">" in the locate function, it's able to locate cases. (But then it's positioned at the smallest case which is not my intention.)
Can anyone help me on this?
Last edited by groverlynn on April 27th, 2018, 6:11 am, edited 2 times in total.
aaronw
Posts: 561
Joined: June 9th, 2016, 9:38 am
Location: Washington, DC

Re: locate function fails

Post by aaronw »

If the relational operators are < or <=, then the file is positioned at the case with the largest key which satisfies the condition. If the relational operators are > or >=, then the file is positioned at the case with the smallest key which satisfies the condition. However, if GEO_CODE+LISTER contained the last case you'd already have your answer.

Try an empty forcase to loop through all the values. The last case will be loaded in memory.
    forcase SIMPLECAPI_DICT do
    enddo;

    numeric lastCase = HOUSEHOLD_ID;
Gregory Martin
Posts: 1777
Joined: December 5th, 2011, 11:27 pm
Location: Washington, DC

Re: locate function fails

Post by Gregory Martin »

There are other ways to do this. For example, you could use the set last statement (see here: http://www.csprousers.org/help/CSPro/se ... ement.html):
set last(SURVEY_DICT);
loadcase(SURVEY_DICT);
You could also get a list of the keys and then load the last one, like this:
PROC GLOBAL

list string myKeys;

PROC EXAMPLE

    keylist(SURVEY_DICT, myKeys);

    if length(myKeys) > 0 then

        locate(SURVEY_DICT, =, myKeys(length(myKeys)));
        loadcase(SURVEY_DICT);

    endif;
groverlynn
Posts: 6
Joined: March 23rd, 2018, 10:14 pm

Re: locate function fails

Post by groverlynn »

Gregory Martin wrote:There are other ways to do this. For example, you could use the set last statement (see here: http://www.csprousers.org/help/CSPro/se ... ement.html):
set last(SURVEY_DICT);
loadcase(SURVEY_DICT);
You could also get a list of the keys and then load the last one, like this:
PROC GLOBAL

list string myKeys;

PROC EXAMPLE

    keylist(SURVEY_DICT, myKeys);

    if length(myKeys) > 0 then

        locate(SURVEY_DICT, =, myKeys(length(myKeys)));
        loadcase(SURVEY_DICT);

    endif;
Thanks for your reply, but I don't think any of the method solves my problem.
My case ID is not continuous globally, but only continuous within every sub-region (here, GEO_CODE+LISTER). E.g. the existing IDs can be 1001-1040, 1501-1560, 2201-2250.
Now if I want to start a new case in region 15**, so it should be 1561.
By your first method, you will locate at 2250, and get me started at 1551
By your second method, you won't even be able to load the case
groverlynn
Posts: 6
Joined: March 23rd, 2018, 10:14 pm

Re: locate function fails

Post by groverlynn »

aaronw wrote:If the relational operators are < or <=, then the file is positioned at the case with the largest key which satisfies the condition. If the relational operators are > or >=, then the file is positioned at the case with the smallest key which satisfies the condition. However, if GEO_CODE+LISTER contained the last case you'd already have your answer.

Try an empty forcase to loop through all the values. The last case will be loaded in memory.
    forcase SIMPLECAPI_DICT do
    enddo;

    numeric lastCase = HOUSEHOLD_ID;
Thanks for your help. But I think you didn't understand my question. I'm not looking for the last case of ALL cases, but last case given certain conditions.
I have case keys GEO_CODE+LISTER+HH_NO. So I want to find the case with the largest HH_NO given certain GEO_CODE+LISTER, so I can increment the value of HH_NO for my next case. But the locate function seems to be not working here.
josh
Posts: 2399
Joined: May 5th, 2014, 12:49 pm
Location: Washington DC

Re: locate function fails

Post by josh »

You could add one to LISTER and use strictly less than, <, in the locate. Adding one to LISTER puts you one case past the one you want but with < you will get one case before that. There are some special cases to handle though.

It is possible that there is no case with GEO_CODE and LISTER that match the ones that you searching for so after the loadcase you would need to double check that the GEO_CODE and LISTER of the loaded case match the one that you searching for. For example say you had the following cases:

Code: Select all

GEO_CODE      LISTER      HH_NO
1               1          1
1               1          2
1               3          1
and you were searching for GEO_CODE=1, LISTER=2 you would end up calling locate with 1, 3 and it would find 1,1,2. In that case you would check that the loaded lister (1) against the value you were searching for (2) and since they are different you would treat it is if the locate had failed.

Another issue is if LISTER is already at it's max value then adding one will cause problems. For example if LISTER is a two digit value and you area searching for LISTER=99 then you can't pass 100 for lister. In that case you would add one to GEO_CODE and use that in the call to locate.

Here is what the logic would like. This assumes that GEO_CODE and LISTER are two digit numeric values. If they have different lengths you would have to adjust the lengths in the call to maketext and as well as change the max value for LISTER from 99 to whatever the new length would result in. GEO_CODE_FOUND and LISTER_FOUND are the variables names for geocde and lister in the TPL_HH_DICT. I'm assuming that GEO_CODE and LISTER are the names in the main dictionary.
// Get case that is one greater than one we are searching for
numeric nextGeoCode;
numeric nextLister;
if LISTER  < 99 then
    nextGeoCode = GEO_CODE;
    nextLister = LISTER +
1;
else
    
// Can't increment LISTER since it is already at max so use next GEO_CODE
    nextGeocode = GEO_CODE + 1;
    nextLister =
0;
endif;

if locate(TPL_HH_DICT,<, maketext("%2d%2d", nextGeoCode, nextLister)) then
    
loadcase(TPL_HH_DICT);
    
    
// Make sure that case that was found matches the one we are searching for
    if  GEO_CODE_FOUND = GEO_CODE and LISTER_FOUND = LISTER then
        $ = HH_NO +
1;
    
else
        $ =
1;
    
endif;
else
    $ =
1;
endif;
Post Reply