Announcement

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

  • Foreach and forevalues loop

    Hi,

    I have a list of variables that look as follows: max_1 max_2 max_3. All the numbers in the variables correspond to a certain colour e.g. 1==blue, 2==yellow, 3==orange.

    What I want to do is:

    gen blue=1 if max_1!=.
    gen yellow=1 if max_2!=.
    gen orange=1 if max_3!=.

    and so on.


    I have tried to do this with a loop as follows:

    local colours "blue yellow orange"

    foreach colour of local colours{
    forvalues i = 1(1)3{
    preserve
    gen `colour'_present = 1 if max_`i'!=.
    restore
    }
    }

    however, this does not work because it keeps on looping. Is there a way around this/ or to achieve the same result?

    Thanks






  • #2
    Note first that what you want is one loop (not two!). That's a little hard to see for beginners, but note that your two nested loops would give 3 x 3 = 9 results, but you have just 3 commands to execute.

    Also the preserve and restore commands are utterly pointless here. You create a variable but then throw away the result by going back to the original dataset. So, out they go.

    I'll add that (1, .) indicators are much less useful than (0, 1) indicators.

    Here is one way of what I think you want (or should want).

    Code:
    tokenize "blue yellow orange"
    forval j = 1/3 {
         gen ``j''_present = max_`j' != .
    }
    And here is another.

    Code:
    local colours "blue yellow orange"
    forval j = 1/3 {
         gettoken colour colours : colours
         gen `colour'_present = max_`j' != .
    }
    And here is another.

    Code:
    local j = 1
    foreach colour of local colours {
         gen `colour'_present = max_`j' != .
         local ++j
    }
    PS: I haven't tried it, but I don't think your code would keep on looping. It would be executed and finish, but nothing in the dataset would change.

    Comment


    • #3
      Here is one more solution for looping through parallel lists that relies on the -word count- extended macro function. I personally find the most intuitive the solution below, and Nick's third solution. (Probably because I am not very familiar with -tokenize- and -gettoken-)

      https://www.stata.com/support/faqs/p...arallel-lists/

      Comment


      • #4
        Nick, in your first solution, you did something that puzzles me a bit: you double de-referenced the output of -tokenize-, like this

        gen ``j''_present When I tried single de-referencing, gen `j'_present, it did not work.
        Code:
         . tokenize "blue yellow orange"  . forval j = 1/3 {   2. gen `j'_present = max_`j' != .   3. } 1_present invalid name r(198);
        Can you say a word or two about what is that, and where can one read more about it?

        Comment


        • #5
          It didn’t work because 1_present is an illegal variable name.

          Comment


          • #6
            My question is more why the result of single de-referencing is 1 , rather than blue. In the example below I am obtaining blue, as I would have expected. In your code, I am obtaining 1.

            Code:
            . tokenize "blue yellow orange"
            
            . dis `1'
            blue not found
            r(111);
            
            . dis blue
            blue not found
            r(111);
            The code above illustrates that when I single de-reference the token of tokenize, I obtain what I expect to obtain, blue. But in your code for some reason it does not work like this, and you need to double de-reference.

            Comment


            • #7
              The error message above is irrelevant, I know that blue will not be found because it has not been defined.

              The key is that in the example above, following -tokenize- by `1', I obtain blue. But in your code in the loop, to obtain blue you apparently needed to de-reference twice ``1''.

              Comment


              • #8
                display doesn't work there because there is no variable or scalar called blue. What's relevant after tokenize would be quite different:

                Code:
                display "`1'"
                which shows that the macro with name 1 has value or contents "blue" -- which text is what is used when you give generate the name of the new variable.

                display has an agenda which is to interpret what you feed it. The direct answer about what macros contain is given by macro list.

                #7 Not so. ``j'' when `j' is 1 becomes `1' becomes "blue" -- and so on.
                Last edited by Nick Cox; 26 Nov 2018, 14:15.

                Comment


                • #9
                  OK, thank you. I think I got it.

                  The first de-referencing is needed because of the macro from the loop j.

                  The second is standard de-referencing of the first token of tokenize.

                  So when I am de-referencing only once in the loop, I am obtaining 1, and not `1' which is what I need post tokenize to get blue.

                  Comment

                  Working...
                  X