program define swapval *! 1.0.1 NJC 24 November 1999 version 6.0 gettoken a 0 : 0 unab varlist : `a', min(1) max(2) local nvars : word count `varlist' if `nvars' == 1 { gettoken b 0 : 0 unab varlist: `a' `b', min(2) max(2) } tokenize `varlist' args a b capture confirm string variable `a' local aisnum = _rc > 0 capture confirm string variable `b' local bisnum = _rc > 0 if `aisnum' != `bisnum' { di in r "variables must be compatible types" error 109 } gettoken inif 0 : 0 if "`inif'" != "in" & "`inif'" != "if" & "`inif'" != "" { di in r "incorrect syntax" exit 198 } if "`inif'" == "in" { local n = _N if index("`0'", "l") { local 0 : subinstr local 0 "l" "`n'" } if index("`0'", "f") { local 0 : subinstr local 0 "f" "1" } numlist "`0'", int range(>=-`n' <=`n') sort chkzero `r(numlist)' tokenize `r(numlist)' } else if "`inif'" == "if" { * test whether `if' condition is acceptable qui count if `0' if r(N) == 0 { di in r "no observations" exit 2000 } else local if "if `0'" } nobreak { if "`inif'" == "in" { if `aisnum' { /* both variables numeric */ * I'm guessing here using locals, rather than copying * all values for variable, is usually quicker qui while "`1'" != "" { local 1 = cond(`1' < 0, `n'+`1'+1, `1') local copy = `b'[`1'] replace `b' = `a' in `1' replace `a' = `copy' in `1' mac shift } } else { /* both variables string */ * copy variable to keep leading and trailing spaces tempvar copy local btype : type `b' qui gen `btype' `copy' = `b' qui while "`1'" != "" { replace `b' = `a' in `1' replace `a' = `copy' in `1' mac shift } } } else if "`inif'" == "if" { /* if */ tempvar copy local btype : type `b' qui gen `btype' `copy' = `b' qui replace `b' = `a' `if' qui replace `a' = `copy' `if' } else { * < nothing > => swapping whole variables, so just -rename- tempname copy rename `b' `copy' rename `a' `b' rename `copy' `a' } } /* end nobreak */ qui compress `a' `b' end program def chkzero * 1.0.1 NJC 24 November 1999 * The arguments are sorted. * If the first is >0, we need do nothing but exit gracefully. * If the first is 0, we have found a zero. * If the first is <0, we search our way past the - elements. * Thanks to Bill Gould for an improvement. if `1' > 0 { exit 0 } else if `1' == 0 { di in r "0 invalid obs no" exit 198 } else { local i = 1 local nnum : word count `0' while ``i'' < 0 & `i' < `nnum' { local i = `i' + 1 if ``i'' == 0 { di in r "0 invalid obs no" exit 198 } } } end