Skip to content

Commit

Permalink
New 103 For-Loops material
Browse files Browse the repository at this point in the history
-Added discussion of varlist/numlist
-Discussion of difference btw foreach in vs. of
-Eliminated overlap material from 102, made minor reference/link changes as a result

Conflicts:
	Stata 103/Pseudo-SMCL/Concepts/For-Loops and Macros.do
	Stata 103/SMCL/Concepts/For-Loops and Macros.smcl
	Stata 103/Stata 103.zip
  • Loading branch information
hdiamondpollock authored and mbomby committed Jan 21, 2016
1 parent 0444782 commit 89b1bca
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 251 deletions.
61 changes: 58 additions & 3 deletions Stata 103/Do/Concepts/For-Loops and Macros.do
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,61 @@ if `example' == 1 {
if `trace' set trace on
noi {

foreach var of varlist _all {
display "`var'"
}

}
if `trace' set trace off
}
else if `example' == 2 {
if `trace' set trace on
noi {

foreach var in _all {
display "`var'"
}

}
if `trace' set trace off
}
else if `example' == 3 {
if `trace' set trace on
noi {

foreach i of numlist 10(5)50 {
display "`i'"
}

}
if `trace' set trace off
}
else if `example' == 4 {
if `trace' set trace on
noi {

foreach num in 1 2 3 4 5 {
display "`num'"
}

}
if `trace' set trace off
}
else if `example' == 5 {
if `trace' set trace on
noi {

foreach num of numlist 1/5 {
display "`num'"
}

}
if `trace' set trace off
}
else if `example' == 6 {
if `trace' set trace on
noi {

foreach var in sex age educ {
display "Checking `var' for missing values..."
list hhid `var' if `var == .
Expand All @@ -15,7 +70,7 @@ foreach var in sex age educ {
}
if `trace' set trace off
}
else if `example' == 2 {
else if `example' == 7 {
if `trace' set trace on
noi {

Expand All @@ -27,7 +82,7 @@ foreach var in sex age educ {
}
if `trace' set trace off
}
else if `example' == 3 {
else if `example' == 8 {
if `trace' set trace on
noi {

Expand All @@ -39,7 +94,7 @@ foreach var in sex age educ {
}
if `trace' set trace off
}
else if `example' == 4 {
else if `example' == 9 {
if `trace' set trace on
noi {

Expand Down
199 changes: 82 additions & 117 deletions Stata 103/Pseudo-SMCL/Concepts/For-Loops and Macros.do
Original file line number Diff line number Diff line change
Expand Up @@ -4,144 +4,112 @@

{USE}
/*
{view `"{LOOPS-}##introduction"':1. Introduction}{BR}
{view `"{LOOPS-}##introduction"':1. Variants on foreach}{BR}
{view `"{LOOPS-}##tracing"':2. Tracing}{BR}
{view `"{LOOPS-}##macros"':3. More on Macros}{BR}
{view `"{LOOPS-}##loops"':4. More Loops}
{hline}{marker introduction}
{hline}{marker variants}
{bf:1. Introduction}
{bf:1. Variants on foreach}
{hline}
Let's do a quick review of for-loops and macros. Here is an example of a for-loop:
In {bf:Stata 102}, we introduced the {bf:foreach in} loop, which you
should be familiar with. A simple example:
{TRYITCMD}
foreach i of numlist 1/10 {{BR}
display "Hello world!"{BR}
foreach x in a b c {{BR}
display "`x'"{BR}
}
{DEF}
This repeats the commands enclosed by the braces ({cmd}{ }{txt})
(here, just {cmd:display "Hello world!"})
{cmd:10} times. It's preferable to typing the command 10 times: */

display "Hello world!"
display "Hello world!"
display "Hello world!"
display "Hello world!"
display "Hello world!"
display "Hello world!"
display "Hello world!"
display "Hello world!"
display "Hello world!"
display "Hello world!"
display "Hello world!"

/* The for-loop was less code and more efficient,
and it's easier to update:
if I want to switch {cmd:"Hello world!"} to something else
or make a larger change,
I have to do it just once within the loop instead of 10 times.
The loop is also less error-prone,
because repetitively typing out the same thing can lead to mistakes.
Indeed, there are 11 {cmd:display}s above when I meant 10.
{marker style}A quick detour into style.
Notice that after the left brace ({cmd}{{txt}), I indented once.
The code stayed indented until the right brace ({cmd}}{txt}).
This formatting makes the code more readable;
it's easy to tell what's in the loop and what's not.
In the above loop, each item following "in" is substituted into the macro `x'.
However, there are several very useful variants on this syntax, used
when dealing with lists of variables or numbers.
{TECH}
{COL}For more tips on Stata programming style, see these resources, available on{CEND}
{COL}Box:{CEND}
{BLANK}
{COL}{browse "http://www.stata-journal.com/sjpdf.html?articlenum=pr0018":{it:Suggestions on Stata programming style}}{CEND}
{BLANK}
{COL}{browse "http://faculty.chicagobooth.edu/matthew.gentzkow/research/ra_manual_coding.pdf":{it:RA Manual: Notes on Writing Code}}{CEND}
{BOTTOM}
{hline}{marker varlist}
For-loops and macros are distinct but related concepts.
Every for-loop is associated with its own macro, but not every macro is associated with a for-loop.
The loop above was associated with a local macro ({cmd:`i'}),
though the macro wasn't used inside the loop.
Let's look at an example of {helpb foreach:foreach}
that incorporates its macro within the loop:
Say we want to run a loop for 20 variables, all listed consecutively (var1, var2, ... var20).
If you used {bf:foreach in}, you would have to list them all manually.
However, when using {bf:foreach of varlist}, you can simply tell Stata
to use the 1st through 20th variables, only listing those two with a dash in between.
Thus, this code would tabulate all twenty variables:
{TRYITCMD}
foreach var in sex age educ {
display "Checking `var' for missing values..."
list hhid `var' if `var' == .
{CMD}
foreach i of varlist var1-var20 {{BR}
tabulate `i'{BR}
}
{DEF}
This {cmd:foreach} command loops over the variables {cmd:sex}, {cmd:age}, and {cmd:educ}.
In this dataset, these variables should never have missing values.
For each variable, the loop first displays the variable name as part of a message
({cmd:"Checking `var' for missing values..."}).
It then lists all values of {cmd:hhid} for which the variable is missing.
Knowing these, we can then examine the problematic observations more closely.
If you had tried using this shorthand with {cmd:foreach in}
Stata would get confused and would try to look for a variable that was named "var1-var20",
and would just tell you the loop is impossible to run because that variable doesn’t exist.
Here's another very useful example. Compare the output of: */

This {cmd:foreach} repeatedly sets the local macro {cmd:`var'} to each element in
the list that follows {cmd:in}, executing the commands in the loop for each value of {cmd:`var'}.
{cmd:var} is a name I made up, and I could have chosen something else.
foreach var of varlist _all {
display "`var'"
}

{marker whats_in_a_name}{...}
{TECH}
{COL}{bf:What's in a name?}{CEND}
{MLINE}
{COL}The same rules generally apply to all Stata names, whether it's of a{CEND}
{COL}variable, macro, or something else. From {helpb varname:help varname}:{CEND}
{BLANK}
{COL}"Variable names may be 1 to 32 characters long and must start with {cmd:a-z}, {cmd:A-Z},{CEND}
{COL}or {cmd:_}, and the remaining characters may be {cmd:a-z}, {cmd:A-Z}, {cmd:_}, or {cmd:0-9}."{CEND}
{BLANK}
{COL}The exception to this rule is local macros, which may be 1 to 31 characters{CEND}
{COL}long (a character shorter), but may start with {cmd:0-9}. Global macros (which{CEND}
{COL}we will discuss later) follow the same naming conventions as variables.{CEND}
{BOTTOM}
*and:

foreach var in _all {
display "`var'"
}

The first element in the list is {cmd:"sex"}.
Thus, the local macro {cmd:`var'} is first set to {cmd:"sex"}.
The commands in the loop are then executed:
/* Note that there are many ways to specify a list of variables in Stata. See
this very useful {helpb varlist:help file} for more. In particular, notice
the use of special characters such as "*" to indicate a certain subset
of variables. Can you think of a time when you might use them?
{CMD}
display "Checking {ul:`var'} for missing values..."{BR}
list hhid {ul:`var'} if {ul:`var'} == .
{DEF}
{hline}{marker numlist}
The value of {cmd:`var'} is immediately substituted for {cmd:`var'} in the commands,
so this is the same as:
When we want to loop over a list of numbers, {cmd:foreach of numlist} is a great
shorthand.
{CMD}
display "Checking {ul:sex} for missing values..."{BR}
list hhid {ul:sex} if {ul:sex} == .
Let's look at the following loop:
{TRYITCMD}
foreach i of numlist 1/10 {{BR}
display "`i'"{BR}
}
{DEF}
After {cmd:list},
all the commands in the for-loop have been executed,
so {cmd:`var'} is set to the next element in the list: {cmd:"age"} and then finally {cmd:"educ".}
A numlist ("number list") is a list of numbers specified in shorthand.
The shorthand used above is the one you'll see most frequently.
The / symbol means "to" so 1/10 means 1 to 10: 1/10 is shorthand for 1 2 3 4 5 6 7 8 9 10.
Another useful shorthand allows you to move from one number to another in steps of a third number.
Multiples of a number follow this pattern. For example: */

Don't think of {cmd:display} as searching for and then accessing the contents of the local macro {cmd:`var'}.
Instead, the value of {cmd:`var'} is essentially "copied and pasted" into the command before it is executed.
Stata completes the substitution, replacing {cmd:`var'} with its value,
and {it:then} {cmd:display} is executed.
{cmd:display} has no idea that a local macro was used,
because the substitution was done before the command was executed.
foreach i of numlist 10(5)50 {
display "`i'"
}

/*#1(#d)#2 means "#1 to #2 in steps of #d". Thus, 10(5)50 means 10 to 50 in steps of 5,
in other words, all the multiples of 5 between 10 and 50, inclusive.
These aren't all the numlist shortcuts: see the {help numlist:help file} for more.
{hline}
In Stata, "macros" are objects that can be substituted into commands in this way.
They are not variables;
that term is used in reference to the variables in the dataset,
which have as many values as there are observations.
{bf:Note:} Almost all Stata users will at some point get mixed up between {bf:in} and {bf:of}
when using the {cmd:foreach} command. Remember that when using {bf:in}, you must spell
out all of the items that will be pasted into the resulting macro. Using {bf:of},
when combined with {bf:varlist} or {bf:numlist}, allows you to use some shorthand
specifically when the items that you want to loop through are either all variables
or all numbers.
Some additional terminology: {help quotes:"double quotes"} ({cmd:""}) are used to enclose strings.
For example, {cmd:"abc"}, {cmd:"123"}, and {cmd:"Hello world"} are each a single string enclosed by double quotes.
"Single quotes" ({cmd:`} and {cmd:'}) is the term for the characters used to enclose locals,
such as {cmd:`var'}.
Note how the output of the following two loops are the same: */

foreach num in 1 2 3 4 5 {
display "`num'"
}

foreach num of numlist 1/5 {
display "`num'"
}

{hline}{marker tracing}
/*{hline}{marker tracing}
{bf:2. Tracing}
Expand All @@ -150,8 +118,7 @@ such as {cmd:`var'}.
Loops can be confusing, and they're also difficult to debug,
because for a loop that results in an error,
Stata doesn't clearly indicate which command in the loop is causing the problem.
For example, here's the loop from above,
but with a bug introduced: */
For example, here's a loop with a bug introduced: */

foreach var in sex age educ {
display "Checking `var' for missing values..."
Expand Down Expand Up @@ -352,7 +319,7 @@ foreach var of varlist _all {{BR}

display "The dataset has `i' variables."

/* {...}
/*{...}
{TECH}
{COL}{bf:More on macros}{CEND}
{MLINE}
Expand All @@ -372,11 +339,9 @@ display "The dataset has `i' variables."
{hline}
{cmd:foreach} isn't the only loop or even the only for-loop in
Stata. If you're not already familiar with the very useful variants on {cmd:foreach in},
{cmd:foreach of varlist} and {cmd:foreach of numlist}, check out {bf:Stata 102} for examples.
{helpb forvalues} loops over certain {it:numlists}, and especially abbreviated as
{cmd:forv} or {cmd:forval}, is easier to type than {cmd:foreach of numlist}. The {helpb while} loop,
is a more advanced, but useful loop that we'll look at below:
Stata. For instance, {helpb forvalues} loops over certain {it:numlists}, and especially abbreviated as
{cmd:forv} or {cmd:forval}, is easier to type than {view `"{LOOPS-}##numlist"':foreach of numlist}.
The {helpb while} loop is a more advanced, but useful loop that we'll look at below:
Instead of designating text/variables/numbers to substitute within the loop,
{cmd:while} simply sets a condition that must be met for the loop to run.
Expand All @@ -389,8 +354,8 @@ while x = true {
}
{DEF}
Try this loop (with a local thrown in for good measure) if you feel comfortable with loops so far.
If you are already confused, it might be best to come back to it later – it’s a bit more advanced. */
Try this loop (with a local thrown in for good measure) if you feel comfortable
with loops so far – its a bit more advanced. */

local i = 1
while `i' < 15 {
Expand Down
3 changes: 1 addition & 2 deletions Stata 103/Pseudo-SMCL/Concepts/if.do
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,7 @@ foreach var of varlist _all {
These are the observation numbers of the two observations with {cmd:hhid "1802011"}.
Touching on {view `"{LOOPS-}##style"':style} again,
notice above that for every left brace, I indented once.
Touching on style, notice above that for every left brace, I indented once.
My code stays indented until the right brace.
Thus, it's easy to tell what's in the loop and what's not, and what's in the {cmd:if} block and what's not. */

Expand Down
Loading

0 comments on commit 89b1bca

Please sign in to comment.