Announcement

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

  • Identifying and storing the iteration number in a FOREACH loop

    Hello,

    I'd like to set a conditional statement based on the first iteration of a FOREACH loop. I am not sure how to identify and store that indexed count, and currently the condition is hard-coded based on the first variable listed in the macro, instead of dynamically based on the first loop.


    local logvars = "f_hdl f_a1c f_race"
    foreach var in `logvars' {

    .....

    graph export "${prog}gph_`var'.tif", replace
    graph save `var'.gph,replace
    gr export temp.png, height(450) width(600) replace
    if `var' == f_hdl {//I'd like to replace this with a index count = 1
    png2rtf using 05_diagnostic_plots.doc, g(temp.png) replace
    }
    else {
    png2rtf using 05_diagnostic_plots.doc, g(temp.png) append

    ....
    }
    Guidance would be appreciated.

    Thank you!
    Preeti
    Last edited by Preeti Gill; 10 Aug 2016, 11:26.

  • #2
    I really don't understand what you want to do here. If you were to change the code to
    Code:
    if `var' == 1 {
    you will be conditioning on whether or not the value of f_hdl, f_a1c or f_race equals 1 in the first observation of the data set. Is that what you want? That would be unusual?

    The more usual situation would be testing whether or not the name of the variable that var represents is equal to f_hdl, f_a1c, or f_race, respectively. That would require testing -if `"`var'"' == whatever-. But I can't make sense of walking the whatever through the loop on each iteration, because `"`var'"' will, necessarily, be f_hdl the first time, f_a1c the second time, and f_race the third time. In other words, the condition will always test true, so you don't even need the -if- statement.

    Can you be more explicit about what you are trying to accomplish here? Or maybe somebody else gets what you want and will respond.

    Comment


    • #3
      I won't try to revise your code. It's incomplete and depends on data and macro definitions we can't use or see and a user-written program that is not explained.

      But here is some technique in a reproducible example. I cycle over both a varlist and a counter.

      Code:
      sysuse auto, clear
      
      local myvars headroom trunk length weight displacement
      
      local j = 1
      
      foreach v of local myvars {
          di `j'
          
          su `v'
          
          local ++j
      }
      If that's not what you want, please use a reproducible example and clarify the question.

      NOTE: Clyde made essentially similar points.
      Last edited by Nick Cox; 10 Aug 2016, 12:04.

      Comment


      • #4
        Hi Nick and Clyde,

        Thank you for your input! Nick's feedback provides what I hoped to implement. If I change the variable list, I still want the conditional statement to execute the ,replace (associated with the if {}) for the first item in the macro variable 'vars', and the append for the rest of the items in that macro variable (associated with the else{}). In other words, I don't want to set `var' == named_variable, but rather check for whether `var' == first_loop.


        Here is how I revised the code:

        local logvars = "f_hdl f_a1c f_race"
        local j = 1
        foreach var in `logvars' {

        .....

        graph export "${prog}gph_`var'.tif", replace
        graph save `var'.gph,replace
        gr export temp.png, height(450) width(600) replace
        if `j' == 1 {
        png2rtf using 05_diagnostic_plots.doc, g(temp.png) replace
        }
        else {
        png2rtf using 05_diagnostic_plots.doc, g(temp.png) append


        local ++j
        ....
        }
        Best,
        Preeti

        Comment


        • #5
          Clyde & Nick's approach is fine, and quite easy to generalise.

          Another way of amending a command inside a loop so that the first run is different from all others is to set up a local macro before starting the loop, use it once in the loop , and then change it inside the loop:
          Code:
          local app_rep replace
          local logvars = "f_hdl f_a1c f_race"
          foreach var in `logvars' {
          
          .....
          
          graph export "${prog}gph_`var'.tif", replace
          graph save `var'.gph,replace
          gr export temp.png, height(450) width(600) replace
          png2rtf using 05_diagnostic_plots.doc, g(temp.png) `app_rep'
          local app_rep append
          
          ....
          }
          Now, on the first run, `app_rep' is is read as replace and the key line is
          Code:
          png2rtf using 05_diagnostic_plots.doc, g(temp.png) replace
          On subsequent runs, `app_rep' is is read as append and the key line is
          Code:
          png2rtf using 05_diagnostic_plots.doc, g(temp.png) append
          This is a neat trick when you can use it, but it only works if you just want to make the first run through the loop different.
          Last edited by Paul T Seed; 10 Aug 2016, 13:43.

          Comment


          • #6
            Hi Paul,

            That is neat. I really like it for the purposes of this code. I'm new to Stata and just getting a hang of its style of macro-variables and looping, so your response contrasted with Nick's have been really informative for how macros operate.


            Thanks so much,
            Preeti

            Comment


            • #7
              Another approach to building up a file by serially appending things, that works very nicely for .dta files, but might not work for -png2rtf- is:

              Code:
              clear
              tempfile building
              save `building', emptyok
              
              local vars f_hdl f_alc f_race
              
              foreach v of varlist `vars' {
                  use mydata, clear
                  // CODE TO CREATE SOME DATA THAT GOES INTO `building'
                  // THAT DEPENDS ON `v'
                  append using `building'
                  save `"`building'"', replace
              }
              
              use `building', clear
              // CODE TO CLEAN IT UP AND THEN SAVE AS A PERMANENT FILE
              There is no need in this situation to distinguish the first run through the loop from the others, because the file being appended to starts out as an empty file. The problem of building up a file through serial -append- commands comes up often on this Forum.

              If png2rtf allows you to first create an empty .rtf file, then this approach would work for that as well.


              Comment


              • #8
                Sometimes it's good technique to take the first case out of the loop altogether. Looking at the detailed code leads me to think that's not so here but here's another example.

                We imagine looping over y1 to y5 to find the row maximum. Forget that there is an egen function to do this!

                Code:
                gen max = y1
                
                forval j = 2/5 { 
                     replace max = max(max, y`j') 
                }

                Comment


                • #9
                  This forum is so helpful! I am very pleased to have joined. Thank you all for these multiple teaching moments.

                  My next step will be to look into the "egen" function.

                  Comment

                  Working...
                  X