*! sortobs 1.1 16sep2010 by Julian Reif * 1.1: added before and after options. Removed reverse option program define sortobs, nclass version 8.2 syntax [varname(default=none)], VALues(string asis) [first last before(string) after(string)] ************************ *** ERROR CHECKING *** ************************ * before() error checking if (`"`before'"' != "" & `"`after'"' != "") { dis as error "before() may not be combined with after()" exit 198 } if (`"`before'"' != "" & `"`first'"' != "") { dis as error "before() may not be combined with first()" exit 198 } if (`"`before'"' != "" & `"`last'"' != "") { dis as error "before() may not be combined with last()" exit 198 } * after() error checking if (`"`after'"' != "" & `"`first'"' != "") { dis as error "after() may not be combined with first()" exit 198 } if (`"`after'"' != "" & `"`last'"' != "") { dis as error "after() may not be combined with last()" exit 198 } * first/last error checking if ("`first'" != "" & "`last'" != "") { dis as error "first may not be combined with last" exit 198 } * Count number of observations qui count local num_obs = `r(N)' * string/numlist error checking if "`varlist'"=="" { numlist `"`values'"', integer foreach opt in before after { if `"``opt''"'!="" { confirm integer number ``opt'' if !inrange(``opt'',1,`num_obs') { di as error "invalid number for `opt'()" exit 198 } } } } **************************** *** Sorting *** **************************** tempvar row_num index * first is the default if no location options specified if `"`first'`last'`before'`after'"'=="" local first "first" * If user specified strings then convert them to numlists if "`varlist'"!="" { qui gen `row_num' = . tokenize `"`values'"' qui while `"`1'"'!= "" { replace `row_num' = . * Error check the input. Allow non-unique values cap confirm string var `varlist' if _rc==0 qui count if `varlist' == `"`1'"' else qui count if `varlist' == `1' if `r(N)' == 0 { di as error "`1' is not a valid value for `varlist'" exit 198 } * Store the row number(s) if _rc==0 replace `row_num' = _n if `varlist'== `"`1'"' else replace `row_num' = _n if `varlist'== `1' levels `row_num' if !mi(`row_num'), local(val) local my_numlist "`my_numlist' `val'" macro shift } * Convert before() or after() to row nums if applicable; enforce uniqueness qui foreach opt in before after { qui replace `row_num' = . if "``opt''"!="" { qui count if `varlist'=="``opt''" if `r(N)'!=1 { di as error `"``opt'' is not a valid value"' exit 198 } replace `row_num' = _n if `varlist'==`"``opt''"' levels `row_num' if !mi(`row_num'), local(`opt') } } } else { numlist "`values'", integer local my_numlist "`r(numlist)'" } local num_vars: word count `my_numlist' qui gen `index' = . * Define first row for sorted variables if "`first'"!="" local first_row = 1 else if "`last'"!="" local first_row = `num_obs' - `num_vars' + 1 else if "`before'"!="" local first_row = `before' - `num_vars' else if "`after'"!="" local first_row = `after'+1 * Count number of vars being sorted local end_row = `first_row' + `num_vars' * Order the rows tokenize "`my_numlist'" local counter = 1 while "`1'"!= "" { qui replace `index' = `counter' in `1' local counter = `counter'+1 macro shift } * Order observations before and after the specified the values if "`last'"!="" qui replace `index' = 0 if mi(`index') else if "`before'"!="" qui replace `index' = 0 if mi(`index') & _n < `before' else if "`after'"!="" qui replace `index' = 0 if mi(`index') & _n <= `after' qui replace `index' = `counter' if mi(`index') * Sort values sort `index', stable end ** EOF