Announcement

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

  • Foreach var of varlist VS. foreach var in

    When I write loops that go through many variables I usually use:

    Code:
    foreach var of varlist varname1 varname2 varname3 {
    I was discussing with a friend of mine and she typically uses

    Code:
    foreach var in varname1 varname2 varname3 {
    What is the difference between these two? When would you prefer var of varlist to in (and vice versa) when looping through unabbreviated variables?

  • #2
    When using -of varlist- in your first example Stata will check already when entering the loop whether the names listed (varname1 varname2 varname3) actually represent names of variables of your current dataset and will issue an error message if not:
    Code:
    sysuse auto
    foreach var of varlist mpg rep78 prize {
       di _n as res "--- summary of `var': -----"
       sum `var'
    }
    whereas when using -in-, instead, Stata will check only when trying to execute -sum `var'- whether the local macro `var' represents a variable of the current data set:
    Code:
    sysuse auto
    foreach var in mpg rep78 prize {
       di _n as res "--- summary of `var': -----"
       sum `var'
    }
    It would be interesting to see which arguments each of you used to defend your approach.
    Last edited by Dirk Enzmann; 09 May 2016, 10:33.

    Comment


    • #3
      Lucia: Please note the request for full real names here, especially

      http://www.statalist.org/forums/help#realnames

      http://www.statalist.org/forums/help#adviceextras #3

      Taking your second syntax first:

      Code:
       foreach var in varname1 varname2 varname3 {
      This is utterly literal. foreach doesn't even notice or care that what you list are variable names. It just cycles over precisely the tokens you supply.

      The first syntax


      Code:
       foreach var of varlist varname1 varname2 varname3 {
      is different in principle as the syntax will first check whether that is indeed a varlist before the loop is even entered. It's not even necessarily the same in practice as -- unless you have set varabbrev off -- foreach will accept e.g. varname1 as an unambiguous abbreviation of a variable name whenever it is, indeed, an unambiguous abbreviation.

      In practice, whenever the two constructs are equivalent, there isn't usually a good reason to prefer one to the other so far as I can see.


      Comment


      • #4
        FWIW, there is yet a third way to loop over variables. That is to place the variable names in a local macro and then loop with -foreach v of local macro_name-.

        I have become partial to this third way. Why? Sometimes when writing a do-file, you don't know the exact names of the variables ahead of time. (And in .ado files you almost never know the names of the variables in advance, nor how many there will be.) It may depend on previous computations in some way; it may be generated "on the fly." Sometimes, it turns out that the set of variables you need to apply your looped code to is empty.

        Code:
        // OK, EVEN IF macro_name IS EMPTY
        // GRACEFULLY SKIPS ENTIRE LOOP
        foreach v of local macro_name { 
            do whatever with `v'
        } 
        
        // BUT
        
        ​foreach v of varlist `macro_name' { // SYNTAX ERROR IF macro_name IS EMPTY
        
        foreach v in `macro_name' { // SYNTAX ERROR IF macro_name IS EMPTY
        Since this "maybe there aren't any variables that need this" situation arises frequently in my work, I have developed the habit of using the -foreach v of local...- approach. I have never observed it to have any particular drawbacks in terms of speed, nor any other difficulties. The expansion of wildcard variable lists is usually taken care of by whatever command creates local macro_name beforehand (e.g. -ds-, -unab-, etc.)

        Comment


        • #5
          Clyde is right, but here's a footnote.

          ds does not offer a local() option although you can follow by copying r(varlist) into a local macro. At this distance, I can't recollect why not.

          That's remedied in findname (SJ), a personal rewrite of ds.

          Comment


          • #6
            Hello Stata Experts,
            I want to do a univariate analysis and to instruct stata to tabulate categorical variables and summarize continuous variables. But it keeps executing tabulate and summarize for all the variables. Here is my code

            ds, has(type string)
            cap drop `r(varlist)'

            ds, has(vallabel)
            local cate `r(varlist)'

            ds, not(vallabel)
            local cont `r(varlist)'

            foreach vr of varlist _all {
            foreach ca of local cate {
            if `vr' == `ca' {
            tabulate `vr'
            continue, break
            }
            }
            else {

            foreach co of local cont {
            if `vr' == `co' {
            summarize `vr'
            continue, break
            }
            }
            }
            }
            log close _all

            I need help please.

            Comment


            • #7
              Your punishment is being given what you asked for. The outer loop has no rationale.

              Code:
              foreach vr of varlist _all {
              foreach ca of local cate {
              if `vr' == `ca' {
              tabulate `vr'
              continue, break
              }
              }
              else {
              
              foreach co of local cont {
              if `vr' == `co' {
              summarize `vr'
              continue, break
              }
              }
              }
              }
              should be

              Code:
              foreach ca of local cate {
                     tabulate `ca'
              }
              
              foreach co of local cont {
                     summarize `co'
              }
              except that those loops aren't needed either:


              Code:
              tab1 `cate'
              summarize `cont'
              Last edited by Nick Cox; 31 Jan 2019, 14:01.

              Comment


              • #8
                Hi Nick,

                I was trying to follow your explanation here, but I'm running into a bit of an issue.

                Code:
                local f `r(A01 A05 A07 A08 A09 B02 B03 B07)'
                tab1  `f'
                I was hoping this syntax would tabulate this list of variables for me, but I keep receiving the error "varlist required" after running the code. What am I doing wrong?

                Thank you!

                Comment


                • #9
                  I didn't suggest that and it's not legal. What's wrong with this?

                  Code:
                  tab1 A01 A05 A07 A08 A09 B02 B03 B07
                  r(varlist) is the name of an r-class result, sometimes. I can't think that r() with variable names inserted has any standing whatsoever in Stata.
                  Last edited by Nick Cox; 06 Jun 2019, 01:29.

                  Comment


                  • #10
                    That works great, thank you!

                    I'd still like to better understand the code proposed above. Essentially, I was trying to recreate what you proposed above:
                    Code:
                     
                     tab1 `cate'
                    I understood `cate' to be a local macro, and therefore was trying to create a local macro to represent my varlist and then be able to tabulate the variables of interest. Clearly I'm missing something, could you explain what `cate' is in the problem above?

                    Many thanks.

                    Comment


                    • #11
                      cate was defined in #6 as what Adebayo Samuel (?Samuel Adebayo) was doing. It doesn't necessarily apply to your problem.

                      All I can gather from your question in #8 is that you want a set of one-way tables for a bundle of variables, and if that is all that is to be done, you don't (have an obvious) need to define any local macros at all.

                      Comment

                      Working...
                      X