Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Loops with multiple branches

    Hello Statalist.

    I have trouble understanding exactly how a specific loop function works. I am doing a loop that can have two outcomes; either the loop is run and a pdf is created in one way or the loop runs but creates a different pdf. My problem is, that the loop seemingly ignores my if/else statement and always jumps to my last statement even if countcheck is smaller than .8 but this is, of course, because I am missing something important. This is what I've been doing:

    Code:
    local dta : dir . files "*.dta"
    local dta : subinstr local dta ".dta" "", all
    foreach x of local dta {
    use `x'.dta, clear
    capture putpdf clear
    putpdf begin
    putpdf paragraph, halign(left)
    
    if countcheck<.8 {
         putpdf text ("Sample is too small")
         putpdf save `x'.pdf, replace
         }
         else {
         putpdf text ("A lot of words I don't want to write here")
         putpdf save `x'.pdf, replace
         }
    }

    For a more generalized version, consider this:

    Code:
    sysuse auto, clear
    levelsof rep78, local(rep)
    foreach x of local rep {
    
    sum price if rep78==`x'
    
    
    if `r(mean)'<5000 {
    di "fish"
    }
    
    else {
    di "cow"
    }
    }
    Here it works. What am I doing wrong?
    Last edited by Rolf Lund; 23 Aug 2018, 06:07.

  • #2
    What's countcheck? Should we know?

    Comment


    • #3
      Originally posted by Nick Cox View Post
      What's countcheck? Should we know?

      Oh yeah. Countcheck is just a percentage of respondents answered per total in each loop.

      Comment


      • #4
        I don't know about "Oh yeah" because I don't yet understand.

        So you are checking whether more than 0.8% answered? Or is it a proportion instead?

        More importantly for the code:

        1. If it is a variable you calculate then know that your code is interpreted as
        Code:
        if countcheck[1] < 0.8
        2. If it is scalar, then that problem doesn't arise.


        Comment


        • #5
          Okay, it’s because I am super bad at asking the precise question. I will try to ask better.

          My question can probably be reduced to this;

          How do I make sure that the loop only goes as far as the “if”-statement for where that condition is true but keeps going when the “else”-statement is true. My problem is, that if I end the if-statement with double curly brackets, does that not entail that the loop always end after the “if” and that it never gets to go to else?

          Comment


          • #6
            Now I read my comment again and it makes very little sense. It is because I struggle with the concept that this is extraordinarily hard to explain. I will give it another go.

            In my loop, I want it to end early if the statement is true and keep going for the rest. I want it to do this:

            Code:
             local dta : dir . files "*.dta"
            local dta : subinstr local dta ".dta" "", all
            foreach x of local dta {
            use `x'.dta, clear
            capture putpdf clear
            putpdf begin
            putpdf paragraph, halign(left)  
            if countcheck<.8 {      
            putpdf text ("Sample is too small")      
            putpdf save `x'.pdf, replace      
            END THE LOOP HERE FOR THE `x' iteration IF THE "IF"-STATEMENT IS TRUE BUT KEEP GOING IF THE STATEMENT IS FALSE      
            }      
            else {      
            putpdf text ("A lot of words I don't want to write here")      
            putpdf save `x'.pdf, replace      
            }
            }

            Comment


            • #7
              But you don't explain what countcheck is? Is it a variable in the dataset? If so, does it have the same value for every observation? Right now, your if command is run exactly one time per dataset, and if countcheck is a variable in the dataset, it is comparing the value of countcheck in the first observation to 0.8. And if countcheck is not a variable in the dataset, you have not shown us where it comes from.

              Is that what you want? If not, what is countcheck? You do not show it in your code, which is why it appears to be a variable in your dataset.

              Comment


              • #8
                Going on the clue in post #3, you probably want countcheck to be some value calculated once per loop.
                That would suggest it would need to be a local, and the problem is it is not defined, nor called as a local (i.e., as `countcheck')
                If you want e.g., for countcheck to be the mean or sum of a variable calculated over values included in your loop, it is not enough to just name the variable. You have to tell Stata what the content of countcheck should be, and if you want better help here, you should also explain us what the content of it should be.

                Comment


                • #9
                  Sorry. As Nick mentioned, the variable is a constant and thus:

                  Code:
                   
                   if countcheck[1] < 0.8
                  Just results in looking at the first value and checking if that below .8. The first value is the same all the way through.

                  My problem is, I think, that my "if"-statement only allows my code to follow that path until it finishes and then keeps going for the rest of the loop. How do I end the loop just after the if-statement for those that fall into that category so that all the rest of the loop is skipped?

                  Comment


                  • #10
                    Perhaps what you want is something like this.
                    Code:
                    if countcheck<.8 {
                         putpdf text ("Sample is too small")
                         putpdf save `x'.pdf, replace
                         continue
                         }
                         else {
                         putpdf text ("A lot of words I don't want to write here")
                         putpdf save `x'.pdf, replace
                         }
                    From the output of help continue

                    The continue command within a foreach, forvalues, or while loop breaks execution of the current loop iteration and skips the remaining commands within the loop. The continue command within a foreach, forvalues, or while loop breaks execution of the current loop iteration and skips the remaining commands within the loop.
                    In the code you presented in post #1, this should not be necessary, because if countcheck<.8, after creating the "Sample is too small" pdf, everything else in the loop that is reading the files is shielded by the else command and should not be executed. But perhaps your post #1 doesn't accurately represent your code.

                    If I have not understood correctly, then you need need to produce a simplified example that, when run, shows us in the Results window what happens. Try the following code, copy and paste the output from the Results window into your next post, and explain what differs from what you want.
                    Code:
                    local dta : dir . files "*.dta"
                    local dta : subinstr local dta ".dta" "", all
                    foreach x of local dta {
                    use `x'.dta, clear
                    if countcheck<.8 {
                         display "`x'" countcheck " under"
                         }
                         else {
                         display "`x'" countcheck " over"
                         }
                    display "`x'" " last"
                    }

                    Comment

                    Working...
                    X