Statalist


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: st: Submitting a command in a couples of pieces


From   wgould@stata.com (William Gould, StataCorp LP)
To   statalist@hsphsun2.harvard.edu
Subject   Re: st: Submitting a command in a couples of pieces
Date   Thu, 29 Oct 2009 14:03:17 -0500

Adrian Sayers <Adrian.Sayers@bristol.ac.uk> asks, 

> [...] i want stata to ask me a question, then i want to key the 
> response, and then i want stata to run a program. It sounds a little 
> pointless but i am trying read in 3000 odd data files plot them and then 
> trim the file to the relevant section.
> 
> eg.
>      di "What is the first day of data collection?"
>      Type 3
>      di "Day of first data collection = 3"
>      drop if day<3

Martin Weiss <martin.weiss1@gmx.de> replied, 

> *************
>      di "What is the first day of data collection?" _request(day)
>      3
>      di "Day of first data collection =$day "
>      drop if day<$day
> *************

Exactly right.  Let me add a few details.

-_request()- will store the result in a local macro if you prefix its name 
with an underscore, so Martin's answer could have read, 

       di "What is the first day of data collection?" _request(_day)
       3
       di "Day of first data collection =`day' "
       drop if day<`day'

Note that I put -_day- in the -_request()-, but even so, after that, I 
referred to -`day'- just as I usually would.

Here's Martin's answer put into a -program-, which might be an ado-file:


    program trythis
        version 11

        di "What is the day of the data collection?  " _request(_day)
        di "Day of the first data collection = `day'"
        drop if day<`day'
    end


I next suggest to Adrian that if he is going to ask more than one question, 
he must anticipate that users will sometimes mistype their answers.
Most commonly, they will hit Return before typing any answer.  As I result, 
I recommend creating a subroutine to get answers:


    program trythis
        version 11

        askquestion "What is the day of the data collection?"
        local day "`s(answer)'"
        di "Day of the first data collection = `day'"
        drop if day<`day'
    end


    program askquestion, sclass
        args last_line_of_text
        while (1) {
                di as txt "`last_line_of_text' -> " _request(_answer)
                if ("`answer'"=="") { 
                        di as txt "Please answer question, or type" ///
                           as res "qq" as txt "to break."
                }
                else if ("`answer'"=="qq") {
                        exit 1
                }
                else {
                        sreturn local answer "`answer'"
                        exit
                }
        }
    end

In the above code, if the user just presses Return, the question is asked 
again.  The user can type -qq- to have the code break (stop asking questions).

If I were Adrian, I would also check the lexical class of the answer in 
subroutine -askquestion-.  Sometimes answers can be text, even blank, 
and other times they must be numbers, and even integers.  Adrian needs 
to think about the types of the answers he will need.  As a simple example, 
we might modify -askquestion- to allow the caller to specify one of the 
following lexical types:

                text          (meaning a non-blank string)
                number        (any number, and only a number)
                integer       (any number that is an integer)

I would then construct code that looks something like this, 

    program askquestion, sclass
        args lex_class last_line_of_text

        while (1) {
                sreturn clear
                askqustion_ask "`last_line_of_text'"
                local answer  "`s(answer)'"

                if ("`answer'"=="qq") {
                        exit 1
                }

                if ("`answer'"!="") {
                        askquestion_check `lex_class' "`answer'"
                        if (`"s(invalid)'"=="") {
                                sreturn local answer "`answer'"
                                exit
                        }
                }
                else {
                        di as txt "Please answer question, or type" ///
                           as res "qq" as txt "to break."
                }
        }
    end

    program askquestion_ask, sclass
        args text
        di as txt "`text'" -> " _request(_answer)
        sreturn local answer "`answer'"
    end

    program askquestion_check, sclass
        args lex answer

        if ("`lex'"=="text") {
                exit
        }

        if ("`lex'"=="number") {
                capture confirm number `answer'
                if (_rc) {
                        di "You must answer with a number"
                        sreturn local invalid invalid
                }
                exit
        }

        if "`lex'"=="integer") {
                capture confirm number `answer'
                if (_rc) {
                        di "You must answer with an integer"
                        sreturn local invalid invalid
                }
                exit
        }

        di as error "Invalid lexical class -`lex'-"
        di as error "caller has error"
        exit 198
    end


All that said, there's nothing wrong with Martin's original answer if 
Adrian will only be asking a few questions and asking them of himself.

-- Bill
wgould@stata.com
*
*   For searches and help try:
*   http://www.stata.com/help.cgi?search
*   http://www.stata.com/support/statalist/faq
*   http://www.ats.ucla.edu/stat/stata/



© Copyright 1996–2014 StataCorp LP   |   Terms of use   |   Privacy   |   Contact us   |   What's new   |   Site index