I would like to have an if condition in Stata which runs the code in braces for a certain variable only if that variable's name is contained in a local. E.g.
if (`variable` element of `variablenames_local`) {
gen variable2 = variable + 2
}
How can this be done in Stata?
You can use extended macro functions for that, which are documented in help extended_fcn. In this case help macrolist is very useful. (I never remember the names of those help-files, instead I usually type help macro or help local and follow the links in that help-file.)
sysuse auto, clear
local vars "price mpg foreign"
foreach var of varlist _all {
if `: list var in vars' {
di "do something smart with `var'"
}
}
// alternatively:
foreach var of varlist `vars' {
di "do something smart with `var'"
}
Related
I've been on this problem for a couple of hours, I'm new to coding, so excuse me if it's a very simple question.
So I have a list of text and I want to find if there is one of the regular expression from the other sheet in every cell.
If yes, paste the regular expression next to the text.
Example:
For the first row:
7063 BIO PLANET LIEGE.
--> i'd like it to write "BIO PLANET" in the cell to the right. (Because BIO PLANET is one of the regular expression to test from the second sheet).
I wrote something like this, but couldn't really figure out what needs to be fixed:
function ExpenseMatching() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet1 = spreadsheet.getSheetByName("Import2");
var sheet2 = spreadsheet.getSheetByName("Regular Expression");
for ( i =1; i<24 ; i++)
{
//Browser.msgBox(i)
var test1 = sheet2.getRange("A"+ i);
var test2 = sheet1.getRange("A2");
var test = new RegExp(test1).test(test2);
if (regexp==true)
{
test1.copyTo(sheet1.getRange("I2"));
Browser.msgBox(test)
}
else
{
}
}
}
Thanks is advance for your help guys !
You want to retrieve the values of the column "A" on the sheet Import2 and the values of the column "A" on the sheet Regular Expression.
You want to check whether the values of Import2 includes the values of Regular Expression. When the values of Import2 includes the values of Regular Expression, you want to put the value of Regular Expression to the column "B" on Import2.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer?
Modification points:
In your script,
if (regexp==true) doesn't work and an error occurs. Because regexp is not declared.
This has already been mentioned by Rubén's comment.
From your question, I thought that you want to put the result value to the column "B" of Import2. But it seems that your script puts the value to the column "I" from test1.copyTo(sheet1.getRange("I2")).
Your script checks only "A2" of Import2.
Each row is checked and copy the value in the for loop. In this case, the process cost will be high.
When above points are reflected to your script, how about the following modified script?
Modified script:
function ExpenseMatching() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet1 = spreadsheet.getSheetByName("Import2");
var sheet2 = spreadsheet.getSheetByName("Regular Expression");
const values1 = sheet1.getRange(`A2:A${sheet1.getLastRow()}`).getValues();
const values2 = sheet2.getRange(`A2:A${sheet2.getLastRow()}`).getValues();
const res = values1.map(([r1]) => {
for (let i = 0; i < values2.length; i++) {
if (new RegExp(values2[i][0]).test(r1)) {
return [values2[i][0]];
}
}
return [""];
});
sheet1.getRange(2, 2, res.length, 1).setValues(res);
}
I think that in your situation, you can also use if (r1.includes(values2[i][0])) { instead of if (new RegExp(values2[i][0]).test(r1)) {. This might be able to reduce more cost.
Note:
In this modification, the result values are put to the column "B" of Import2.
Please run the script with enabling V8.
References:
map()
setValues()
I have the following dataset:
* Example generated by -dataex-. To install: ssc install dataex
clear
input float(MA_234_AAF_US AL_87665_ACH_USA TX_3_GH_US LA_689_KLO_US KY_3435_Z_USA)
9.96567 10.559998 12.935112 13.142867 9.35608
9.758375 9.856 10.002945 8.090142 10.313352
11.594983 9.274136 12.486753 6.661111 10.529528
10.354564 9.893115 10.625778 13.265523 7.405652
12.7978 10.76272 11.527348 10.112844 11.64973
10.63846 11.040354 8.569465 8.781206 11.448466
9.254233 13.808356 10.817062 9.545164 8.759109
11.8417 10.15155 12.72436 11.102546 11.506034
9.864883 9.864952 14.45111 10.12562 9.753519
9.965327 11.517155 9.910269 8.988406 11.359774
end
I would like to change the order of the text in the variable names like this:
US_MA_AAF_234 USA_AL_ACH_87665 US_TX_GH_3 US_LA_KLO_689 USA_KY_Z_3435
I have tried the code provided in the answers in this question:
Remove middle character from variable names
However, I could not make it work.
Here is an alternative approach.
It's inferior to using rename in one line, which addresses the purpose well. Scrutiny will show the necessary correspondence with that approach. It hinges on the names being elements separated by underscores, which are removed and then reinserted.
clear
input float(MA_234_AAF_US AL_87665_ACH_USA TX_3_GH_US LA_689_KLO_US KY_3435_Z_USA)
9.96567 10.559998 12.935112 13.142867 9.35608
end
foreach name of var * {
local new = subinstr("`name'", "_", " ", .)
tokenize `new'
rename `name' `4'_`1'_`3'_`2'
}
describe, fullnames
Contains data
obs: 1
vars: 5
size: 20
-------------------------------------------------------------------------------------------
storage display value
variable name type format label variable label
-------------------------------------------------------------------------------------------
US_MA_AAF_234 float %9.0g
USA_AL_ACH_87665
float %9.0g
US_TX_GH_3 float %9.0g
US_LA_KLO_689 float %9.0g
USA_KY_Z_3435 float %9.0g
-------------------------------------------------------------------------------------------
EDIT:
As #PearlySpencer points out, the statements within the loop
local new = subinstr("`name'", "_", " ", .)
tokenize `new'
rename `name' `4'_`1'_`3'_`2'
could be replaced by
tokenize `name', parse(_)
rename `name' `7'_`1'_`5'_`3'
The difference is that the underscores will get placed in local macros 2, 4, 6.
I am trying to label a batch of variables using a loop as follows, but failed with stata error "invalid syntax". I couldn't find out where went wrong.
local myvars "basicenumerator" "basicfr_gpslatitude" "basicfr_gpslongitude"
local mylabels "Name of enumerator" "the latitude of the farmers house" "the longtitude of the farmers house"
local n : word count `mylabels'
forvalues i = 1/`n'{
local a: word `i' of `mylabels'
local b: word `i' of `myvars'
label var `b' "`a'"
}
To debug this, the main trick is to get Stata to show you what it thinks the local macros are. This script makes your code reproducible and also fixes it.
clear
set obs 1
gen basicenumerator = 42
gen basicfr_gpslatitude = 42
gen basicfr_gpslongitude = 42
local myvars `" "basicenumerator" "basicfr_gpslatitude" "basicfr_gpslongitude" "'
local mylabels `" "Name of enumerator" "the latitude of the farmers house" "the longtitude of the farmers house" "'
local n : word count `mylabels'
mac li
forvalues i = 1/`n'{
local a: word `i' of `mylabels'
local b: word `i' of `myvars'
label var `b' "`a'"
}
The problem is that the outer " " get stripped in defining your locals, so to keep the " " as desired, you need to wrap each string within compound double quotes.
For explanation, see http://www.stata.com/manuals14/u12.pdf 12.4.6.
Picky correction: spelling is longitude.
To cleanup data, I am writing a function which takes a list of variables, and replaces a list of strings with empty strings. While I have code to solve the problem, I want to learn how to use a variable length list of strings as an argument.
To get a sense of the simple version, the following would replace any "X" in myval1 and myval2 with an empty string, and is called like:
replace_string_with_empty myval1 myval2, code("X")
The code is,
capture program drop replace_string_with_empty
program replace_string_with_empty
syntax varlist(min=1), Code(string)
foreach var in `varlist' {
replace `var' = "" if `var' == "`code'"
}
end
But what if I have several codes? Forgetting that there may be cleaner ways to do this, I would like to call this as things like
replace_string_with_empty myval1 myval2, codes("X" "NONE")
But I can't figure out the type in the syntax command, etc. For example, the following does not work
capture program drop replace_string_with_empty
program replace_string_with_empty
syntax varlist(min=1), Codes(namelist)
foreach var in `varlist' {
foreach code in `codes' {
replace `var' = "" if `var' == "`code'"
}
}
end
Any ideas? (again, I am sure there are better ways to solve this exact problem, but I want to figure out how to use the syntax in this way for other tasks as well.
Here's a simple example of one approach to this. The asis option will leave the quotes alone, but we will then need to use compound quotes when referring to the strings that are to be recoded to null:
capture program drop replace_string_with_empty
program replace_string_with_empty
syntax varlist(min=1 string), Codes(string asis)
tokenize `"`codes'"'
while "`1'" != "" {
foreach var of varlist `varlist' {
replace `var' = "" if `var'==`"`1'"'
}
macro shift
}
end
sysuse auto, clear
clonevar make2=make
replace_string_with_empty make*, codes("AMC Concord" "AMC Spirit" "Audi 5000")
I have created the following program which is not playing well with string expressions. I haven't been able to figure out the right adjustment to add in my syntax definition to get this to work as intended.
I think this is something small, but I haven't been able to get it right yet. Or, references to something that would help would also be appreciated.
Included is the program and some dummy code that yields the same error.
Thanks!
cap program drop repl_conf
program define repl_conf
syntax varlist =exp [if]
qui count `if'
if r(N) ==0 {
di as err "NO MATCHES -- NO REPLACE"
exit 9
}
else {
noi dis "SUCCESSFUL REPLACE of >=1 OBS -- " r(N) " OBS replaced"
qui replace `varlist' `exp' `if'
}
end
sysuse auto, clear
repl_conf length=999 if length==233
repl_conf make="ZZZ" if make=="AMC Concord"
type mismatch
r(109);
This gets further. I moved the second message so that it is only issued if the replace was successful.
program define repl_conf
gettoken varname 0 : 0, parse(=)
confirm var `varname'
gettoken eq 0 : 0, parse(=)
syntax anything [if]
qui count `if'
if r(N) == 0 {
di as err "NO MATCHES -- NO REPLACE"
exit 9
}
else {
qui replace `varname' = `anything' `if'
noi di "SUCCESSFUL REPLACE of >=1 OBS -- " r(N) " OBS replaced"
}
end
sysuse auto, clear
repl_conf length=999 if length==233
repl_conf make="ZZZ" if make=="AMC Concord"