PollPenn
PollPenn

Reputation: 733

Is it possible to invoke a global macro inside a function in Stata?

I have a set of variables the list of which I have saved in a global macro so that I can use them in a function

global inlist_cond "amz2002ras_clss, amz2003ras_clss, amz2004ras_clss, amz2005ras_clss, amz2006ras_clss, amz2007ras_clss, amz2008ras_clss, amz2009ras_clss, amz2010ras_clss, amz2011ras_clss"

The reason why they are saved in a macro is because the list will be in a loop and its content will change depending on the year.

What I need to do is to generate a dummy variable so that water_dummy == 1 if any of the variables in the macro list has the WATER classification. In Stata, I need to write

gen water_dummy = inlist("WATER", "$inlist_cond")

, which--ideally--should translate to

gen water_dummy = inlist("WATER", amz2002ras_clss, amz2003ras_clss, amz2004ras_clss, amz2005ras_clss, amz2006ras_clss, amz2007ras_clss, amz2008ras_clss, amz2009ras_clss, amz2010ras_clss, amz2011ras_clss)

But this did not work---the code executed without any errors but the dummy variable only contained 0s. I know that it is possible to invoke macros inside functions in Stata, but I have never tried it when the macro contains a whole list of conditions. Any thoughts?

Upvotes: 1

Views: 446

Answers (2)

Nick Cox
Nick Cox

Reputation: 37208

With a literal string specified, which the double quotes in the generate statement insist on, then you are comparing text with text and the comparison is not with the data at all.

. clear

. set obs 1
number of observations (_N) was 0, now 1

. gen a = "water" 

. gen b = "wine" 

. gen c = "beer" 

. global myvars "a,b,c"

. gen found1 = inlist("water", "$myvars") 

. gen found2 = inlist("water", $myvars) 

. list 

     +---------------------------------------+
     |     a      b      c   found1   found2 |
     |---------------------------------------|
  1. | water   wine   beer        0        1 |
     +---------------------------------------+

The first comparison is equivalent to

. di inlist("water", "a,b,c")
0

which finds no match, as "water" is not matched by the (single!) other argument.

Macro references are certainly allowed within function or command calls: as each macro name is replaced by its contents before the syntax is checked, the function or command never even knows that a macro reference was ever used.

As @Aspen Chen concisely points out, omitting the double quotes gives what you want so long as the inlist() syntax remains legal.

Upvotes: 4

Roberto Ferrer
Roberto Ferrer

Reputation: 11102

If your data structure is something like in the following example, you can try the egen function incss, from egenmore (ssc install egenmore):

clear
set more off

input ///
str15(amz2009 amz2010)
"water" "juice"
"milk" "water"
"lemonade" "wine"
"water & beer" "tea"
end

list

egen watindic = incss(amz*), sub(water)

list

Be aware it searches for substrings (see the result for the last example observation).

A solution with a loop achieving different results is:

gen watindic2 = 0
forvalues i = 2009/2010 {
    replace watindic2 = 1 if amz`i' == "water"
}

list

Another solution involves reshape, but I'll leave it at that.

Upvotes: 2

Related Questions