Buzz Burhans started a thread on problems with
code including nested -foreach- structures,
resolved to his satisfaction by Scott Merryman's
suggestion.
This is a postscript to that thread making
some general and some specific points.
Nested and parallel structures
==============================
1. If you nest two or more -foreach-
loops, the total number of steps
is the _product_ of the number of
steps in the loop, so
foreach i of num 1/2 {
foreach j of num 1/3 {
di "i is `i' and j is `j'"
}
}
entails 2 * 3 steps in total:
i is 1 and j is 1
i is 1 and j is 2
i is 1 and j is 3
i is 2 and j is 1
i is 2 and j is 2
i is 2 and j is 3
2. You can try doing this with nested -for-, but
success is not guaranteed, for the kind of
reasons discussed in another recent thread.
It works in this case:
for X in num 1/2 , noheader : for Y in num 1/3, noheader: di "i is X
and j is Y"
i is 1 and j is 1
i is 1 and j is 2
i is 1 and j is 3
i is 2 and j is 1
i is 2 and j is 2
i is 2 and j is 3
3. -for- by contrast is optimised for stepping
through parallel structures. The total number
of steps is just the number in any of the lists,
as all must have the same length:
for X in any i j k \ Y in num 1/3, noheader: di "X is Y"
i is 1
j is 2
k is 3
4. How do you this with -foreach-?
Sometimes one list is just a transformation
of the other, so you can do the mapping on the fly.
Suppose variables v3-v14 are to be renumbered v1-v12:
foreach n of num 3/14 {
local new = `v' - 2
rename v`n' v`new'
}
(Note here that -v3- has already been -rename-d -v1-
when we try to -rename- -v5- as -v3-.)
Perhaps more commonly, some such trick cannot
be used, or cannot be identified. In essence then,
-foreach- will step through one list and you have to
ensure that it steps through any other list(s) at the same time.
Buzz's example was a nice little illustration
of a nasty little problem. To recap, he
wanted to -rename-
v3-v14
as
preday18 preday15 preday12 preday9 preday7
preday6 preday5 preday4 preday3 preday2 preday1 preday0
for good reasons.
One fairly transparent way to do that is
local i = 0
local suffixes "18 15 12 9 7 6 5 4 3 2 1 0"
foreach v of var v3-v14 {
local i = `i' + 1
local new : word `i' of `suffixes'
rename `v' preday`new'
}
But the same idea can be expressed more
briefly, at the cost of introducing more
programming stuff:
tokenize "18 15 12 9 7 6 5 4 3 2 1 0"
foreach v of var v3-v14 {
rename `v' preday`1'
mac shift
}
To understand the underlying machinery, you
need to know or learn about local macros,
-macro shift- and -tokenize-. The main
idea is that -tokenize- puts the elements
of 18 ... 0 in macros `1', `2', ... We
use the first value and then shift them
all up one, and loop around repeating that.
Nick
[email protected]
*
* For searches and help try:
* http://www.stata.com/support/faqs/res/findit.html
* http://www.stata.com/support/statalist/faq
* http://www.ats.ucla.edu/stat/stata/