Stata The Stata listserver
[Date Prev][Date Next][Thread Prev][Thread Next][Date index][Thread index]

st: RE: a fancier loop


From   "Nick Cox" <[email protected]>
To   <[email protected]>
Subject   st: RE: a fancier loop
Date   Fri, 11 Apr 2003 10:25:53 +0100

Radu Ban

> i have a set of variables gop1-gop9 greval1-greval9 gadd1-gadd9 and
> several more like these, all postfixed from 1 to 9. each postfix has
> a distinct meaning which i want to incorporate in a label.
>
> i wrote this nested loop with paralel lists, but it doesn't run. can
> anyone point the way out?
>
> for 	X in any gop greval gadd gdeda gcl dyrb dyrd dsd dyre
> nop ncl \
> 	Y in any "gross opening" "gross addition by reval."
> 	"gross actual addition" "gross deduc. & adj." "gross closing"
> 	"depr. up to year beg." "depr. during year"
> 	"depr. adj. for sold/discarded" "depr. up to year close"
> 	"net opening" "net closing":
>
> 		for Z in num 1/9 \
> 		T in any "land" "building" "P&M" "transp. equip."
> 		"computers" "others" "subtot"
> 		"cap. work in prog." "total":
> 			label var XZ "fix. ass. T: Y";
>
> or is not possible to accomplish this in one step?

The problem
===========

Several threads over the last few months have
touched on this issue.

-for- is now, in Stata 8, undocumented. My take
is that -for- is now regarded as having more disadvantages
than advantages, including (1) it is slow, as -for- is ado code
and thus interpreted; (2) it fits poorly with the rest of Stata,
having an idiosyncratic syntax, and being difficult to coordinate
with local macros, etc.; (3) it grows badly, as users try to load
more and more on to it; etc.

As it happens, the likely problem with Radu's code is already
explained at
Why do some nested for commands produce an error?
http://www.stata.com/support/faqs/lang/nestfor.html

Moral: do look at the FAQs (-for- anguish questions).

More generally, nested -for- loops on average do
work with a probability which averages mysteriously
close to 1 / e. There is a probabilistic explanation
in Feller's third volume. That's not high enough
for this to be an attractive technique.

Nevertheless, as Radu says, -for- is a command which offers a
structure for problems involving parallel lists.

So how is this done using either -foreach- or -forvalues-?

My answer
=========

My answer is to use -foreach- or -forvalues- to go
through ONE list, and to use some other technique
to go through ANY OTHER lists at the same time.

Example solution: (1) the code
==============================

Here is one way of attacking Radu's problem. There
are four lists in the problems, which come in pairs.

1. the stubs of several groups of variable names

local X "gop greval gadd gdeda gcl dyrb dyrd dsd dyre nop ncl"

2. longer explanations of each group

local Y "gross opening" "gross addition by reval."
"gross actual addition" "gross deduc. & adj." "gross closing"
"depr. up to year beg." "depr. during year"
"depr. adj. for sold/discarded" "depr. up to year close"
"net opening" "net closing"

3. explanations of each variable within each group:

local T "land" "building" "P&M" "transp. equip."
"computers" "others" "subtot" "cap. work in prog." "total"

4. and the numbers 1 to 9.

With those initial definitions, I conjecture
that Radu needs something like this.

Stata 8
-------

local i = 1
foreach x of local X {
	local y : word `i++' of `Y'
	forval j = 1/9 {
		local t : word `j' of `T'
		label var `x'`j' `"fix. ass. `t': `y'"'
	}
}

Stata 7
-------

local i = 1
foreach x of local X {
	local y : word `i' of `Y'
	forval j = 1/9 {
		local t : word `j' of `T'
		label var `x'`j' `"fix. ass. `t': `y'"'
	}
	local i = `i' + 1
}

Example solution: (2) the main idea
===================================

The architecture of this is

* A -foreach- loop cycling through the stubs
in X. As we step through X automatically, we
have to arrange that we pull out each successive
bit which we also need from Y. The way
we did it here was through -word # of-.

* Nested within that, a -forval- loop
cycles through the integers 1/9. As we step
through that list automatically, we have
to arrange that we pull out each successive
bit which we also need from T. Same device
used.

In short, neither -foreach- nor -forval-
offers inbuilt, explicit machinery
for stepping through other lists at the
same time. But that's not necessary:
you can get that by using other devices
alongside.

Example solution: (3) optional extras
=====================================

Another tool relevant here, but which you
can use only once in a given problem,
is -tokenize-. -tokenize- takes
its argument and emits the pieces ("words",
wide sense) as local macros 1, 2, 3, etc., depending
on how many pieces there are. Words are separated
by spaces, unless bound by double quotes or
compound double quotes, so if I

. tokenize a b c

"a" is now the contents of local macro 1, "b" of 2
and "c" of 3, whereas if I

. tokenize a "b c" d

"a" is now the contents of local macro 1, "b c" of
2 and "d" of 3.

Applying this to Radu's problem, we could for
example

tokenize `T'
local i = 1
foreach x of local X {
	local y : word `i++' of `Y'
	forval j = 1/9 {
		label var `x'``j'' `"fix. ass. `t': `y'"'
	}
}

but in this case we gain nothing from that. More
generally, it is not essential for these problems.

A further note is that in Stata 8, you can pick up
a -word # of- some stuff on the fly:

local i = 1
foreach x of local X {
	forval j = 1/9 {
		label var `x'`j' ///
		`"fix. ass. `: word `j' of `T'': `: word `i++' of `Y''"'
	}
}

The key rule for evaluating macros within macros is analogous
to that in elementary mathematics for evaluating
parenthesised expressions: evaluate the innermost macro first.

That's a neat technique, but again an optional extra.

P.S. is this programming?
=========================

We are here in an interesting grey area: is this Stata
programming or not? The literal answer is "No"; a Stata
program is defined (without circularity!) by the fact
that it begins with a -program- statement. Nevertheless,
in order to make progress, users do need to understand
something about local macros and how to manipulate
them. For this, you don't need [P]; I think all you
need is in [U].

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/



© Copyright 1996–2024 StataCorp LLC   |   Terms of use   |   Privacy   |   Contact us   |   What's new   |   Site index