*! version 1.2.0 23Mar2019 Mauricio Caceres Bravo, mauricio.caceres.bravo@gmail.com *! -levelsof- implementation using C for faster processing capture program drop glevelsof program glevelsof, rclass version 13.1 if ( `=_N < 1' ) { di as err "no observations" exit 2000 } global GTOOLS_CALLER glevelsof syntax anything /// Variables to get levels of: [+|-]varname [[+|-]varname ...] [if] [in] , /// [if condition] [in start / end] [ /// Separate(passthru) /// Levels sepparator COLSeparate(passthru) /// Columns sepparator MISSing /// Include missing values LOCal(str) /// Store results in local Clean /// Clean strings /// unsorted /// Do not sort levels (faster) noLOCALvar /// Do not store levels in a local macro (or in r(levels)) numfmt(passthru) /// Number format freq(passthru) /// (not implemented) compute frequency counts store(passthru) /// (not implemented) store in matrix or mata object gen(passthru) /// Save unique levels in varlist NODS DS /// Parse - as varlist (ds) or negative (nods) silent /// Do not try to display levels in console MATAsave /// Save results in mata MATAsavename(str) /// mata save name /// debug(passthru) /// Print debugging info to console compress /// Try to compress strL variables forcestrl /// Force reading strL variables (stata 14 and above only) Verbose /// Print info during function execution _CTOLerance(passthru) /// (Undocumented) Counting sort tolerance; default is radix BENCHmark /// Benchmark function BENCHmarklevel(int 0) /// Benchmark various steps of the plugin HASHmethod(passthru) /// Hashing method: 0 (default), 1 (biject), 2 (spooky) oncollision(passthru) /// error|fallback: On collision, use native command or throw error /// GROUPid(str) /// tag(passthru) /// counts(passthru) /// fill(passthru) /// replace /// ] if ( (`"`matasave'"' != "") & (`"`local'"' != "") ) { disp as err "Option local() not allowed with option -matasave-" exit 198 } if ( (`"`matasavename'"' != "") & (`"`local'"' != "") ) { disp as err "Option local() not allowed with option -matasave()-" exit 198 } if ( `"`matasavename'"' != "" ) local matasave matasave if ( `"`matasavename'"' == "" ) local matasavename GtoolsByLevels if ( `benchmarklevel' > 0 ) local benchmark benchmark local benchmarklevel benchmarklevel(`benchmarklevel') if ( (`"`localvar'"' != "") & (`"`local'"' != "") ) { disp as txt "(option {opt local} ignored with option {nolocalvar})" } if ( ("`ds'" != "") & ("`nods'" != "") ) { di as err "-ds- and -nods- mutually exclusive" exit 198 } * Get varlist * ----------- if ( `"`anything'"' != "" ) { local varlist: copy local anything local varlist: subinstr local varlist "+" " ", all if ( strpos(`"`varlist'"', "-") & ("`ds'`nods'" == "") ) { disp as txt "'-' interpreted as negative; use option -ds- to interpret as varlist" disp as txt "(to suppress this warning, use option -nods-)" } if ( "`ds'" != "" ) { local varlist `varlist' if ( "`varlist'" == "" ) { di as err "Invalid varlist: `anything'" exit 198 } cap ds `varlist' if ( _rc ) { cap noi ds `varlist' exit _rc } local varlist `r(varlist)' local anything: copy local varlist } else { local parse: copy local varlist local varlist: subinstr local varlist "-" " ", all local varlist `varlist' if ( "`varlist'" == "" ) { di as err "Invalid list: `anything'" di as err "Syntax: [+|-]varname [[+|-]varname ...]" exit 198 } cap ds `varlist' if ( _rc ) { local notfound foreach var of local varlist { cap confirm var `var' if ( _rc ) { local notfound `notfound' `var' } } if ( `:list sizeof notfound' > 0 ) { if ( `:list sizeof notfound' > 1 ) { di as err "Variables not found: `notfound'" } else { di as err "Variable `notfound' not found" } } exit 111 } local varlist local anything while ( `:list sizeof parse' ) { gettoken var parse: parse, p(" -") local neg if inlist("`var'", "-") { gettoken var parse: parse, p(" -") local neg - } cap ds `var' if ( _rc ) { local rc = _rc di as err "Variable '`var'' does not exist." di as err "Syntax: [+|-]varname [[+|-]varname ...]" exit `rc' } foreach v of varlist `var' { local anything `anything' `neg'`v' local varlist `varlist' `v' } } } } if ( "`ds'" == "" ) local nods nods * Run levelsof * ------------ local opts `separate' `missing' `clean' `unsorted' `ds' `nods' local sopts `colseparate' `numfmt' `compress' `forcestrl' local sopts `sopts' `verbose' `benchmark' `benchmarklevel' `_ctolerance' local sopts `sopts' `oncollision' `hashmethod' `debug' local gopts gen(`groupid') `tag' `counts' `fill' `replace' local gopts `gopts' glevelsof(`localvar' `freq' `store' /* */ `gen' `silent' `matasave' matasavename(`matasavename')) cap noi _gtools_internal `anything' `if' `in', `opts' `sopts' `gopts' gfunction(levelsof) local rc = _rc global GTOOLS_CALLER "" if ( `rc' == 17999 ) { if ( `:list sizeof varlist' > 1 ) { di as err "Cannot use fallback with more than one variable." exit 17000 } else if ( `"`localvar'`gen'`numfmt'`matasave'"' != "" ) { di as err `"Cannot use fallback with option(s): `localvar' `gen' `numfmt' `matasave'."' exit 17000 } else if ( strpos("`anything'", "-") & ("`ds'" == "") ) { di as err "Cannot use fallback with inverse order." exit 17000 } else { levelsof `varlist' `if' `in', `opts' exit 0 } } else if ( `rc' == 17001 ) { di as txt "(no observations)" exit 0 } else if ( `rc' == 920 ) { disp as err _n(1) "try {opt gen(prefix)} {opt nolocal} or {opt mata(name)} {opt nolocal};" /* */ " see {help glevelsof:help glevelsof} for details" exit `rc' } else if ( `rc' ) exit `rc' if ( (`"`localvar'"' == "") & (`"`matasave'"' == "") ) { mata st_local("vals", st_global("r(levels)")) mata st_local("sep", st_global("r(sep)")) mata st_local("colsep", st_global("r(colsep)")) if ( `:list sizeof varlist' == 1 ) { cap confirm numeric variable `varlist' if ( _rc == 0 ) { local vals: subinstr local vals " 0." " .", all local vals: subinstr local vals "-0." "-.", all } } return local levels: copy local vals return local sep: copy local sep return local colsep: copy local colsep if ( "`local'" != "" ) c_local `local': copy local vals if ( "`silent'" == "" ) di as txt `"`vals'"' * if ( "`silent'" == "" ) mata st_global("r(levels)") } return scalar N = `r(N)' return scalar J = `r(J)' return scalar minJ = `r(minJ)' return scalar maxJ = `r(maxJ)' end