[Date Prev][Date Next][Thread Prev][Thread Next][Date index][Thread index]

Re: st: Using foreach and two local macros

From   Phil Schumm <[email protected]>
To   [email protected]
Subject   Re: st: Using foreach and two local macros
Date   Thu, 7 Aug 2008 12:28:34 -0500

On Aug 7, 2008, at 10:46 AM, Gawrich Stefan wrote:
Looping over parallel lists is indeed a very powerful feature. To keep it flexible you'll often use a second extended function (word count) with the forval command.

local x "1 2"
local y "3 4"
local n : word count `x'
forvalues i = 1/`n' {
local x1 : word `i' of `x'
local y1 : word `i' of `y'
di `x1'+2*`x1'+`y1'

But in my view the syntax has two drawbacks:
1) It needs a lot of lines. So it bloats your do-files expecially when you use it with more than two locals. (I often use it for batch graph creation where variables, selections, titles and settings can make up to ten locals)
2) You have to create new local names inside the loop, which makes it confusing and error prone

So sometimes I find it convenient to use that good old (not longer documented) "for" command again.

When you brought this up 2 years ago:

I pointed out that you can use nested lists as an alternative, and Nick elaborated on that:

IMHO, nested lists are often a better approach. For example, consider

loc foo `" "1 a I" "2 b II" "3 c III" "'
foreach item of loc foo {
tokenize `"`item'"'
di "`1' `2' `3'"


loc l1 1 2 3
loc l2 a b c
loc l3 I II III
for num `l1' \ any `l2' \ any `l3': di "X Y Z"

In the first case, when you construct the macro foo, you are keeping the values 1, a, and I all together as a group, which is much less prone to error than when you have to construct l1, l2, and l3 separately (e.g., the lengths may not match, you may get the ordering of the sub-items messed up, etc.). Thus, if you are constructing your list(s) by hand, I would argue that the former is much better (and much easier to maintain if you have to add/drop parts of each item in the list later on).

Now, if you are in the position where l1, l2, and l3 are generated programmatically, you just need to assemble them into a nested list. Python has a function for this called -zip()-:

>>> l1 = [1,2,3]
>>> l2 = ['a','b','c']
>>> l3 = ['I','II','III']
>>> zip(l1,l2,l3)
[(1, 'a', 'I'), (2, 'b', 'II'), (3, 'c', 'III')]

It would not be difficult to write a Mata function to do this; alternatively, one could imagine StataCorp adding an extended macro function (i.e., something like {local | global} macname : list zip macnames).

-- Phil

* For searches and help try:

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