Hi All, I've created the following macro to generate random IDs/passwords. It essentially constructs a data step with a bunch of output statements. It allows the user to specify the allowed characters, number of passwords and password length. Also included is a check to ensure duplicate IDs/passwords are not included. My question: Is there a more efficient way to accomplish this? Tweaks to my code or a fundamentally different approach? This macro bogs down when asked to generate 10000 or more IDs/passwords. I originally tried to generate a DATALINES statement with the macro (not allowed) and also tried PROC SQL INSERT, which works but isn't any faster. *characters to place in the ID, space delimited; %let allowed = 1 2 3 4 5 6 7 8 9 a b c d e f h i j k m n p r s t u v w x y z; %let numIDs = 100; *number of IDs to create; %let idLen = 6; *number of characters per ID; %macro ran6; /*delimeters for concatenating macro variables*/ %let delim_nospace = %str(); %let delim_space = %str( ); %let numChars = %length(%sysfunc(compress(&allowed,' '))); *num of total characters available; *%put numchars: &numChars; %let used = ; *generate IDs go here to check for duplicates; *output dataset; data id_output; call streaminit(23); *set random seed; length userID $ &idLen.; *this loop controls the number of IDs to generate; %do i = 1 %to &numIDs; *this loop controls the length of an ID; %do j = 1 %to &idLen; *follow http://blogs.sas.com/content/iml/2011/08/24/how-to-generate-random-numbers-in-sas/; %let u = %sysfunc( rand(UNIFORM) ); *u is random decimal; /*sysevalf works because https://communities.sas.com/message/51523#51523*/ %let x = %sysevalf(1 + (&numChars - 1 ) * &u.); *set random into with upper bound eq to number of characters; %let k = %sysevalf(&numChars * &u , ceil) ; *pull a letter fro the allowed list; %let IDPart = %scan(&allowed.,&k, ' '); /*%put u: &u x: &x k: &k IDPart: &IDPart;*/ %if &j = 1 %then %let userID = &IDPart; /*concatenate macro variables, see https://communities.sas.com/message/180272 */ %else %let userID = %sysfunc(catx(&delim_nospace.,%nrstr(%superq(userID)),%nrstr(%superq(IDPart)))); %end; /*if duplicate found, do not increment i*/ %if %index(&used, &userID) %then %let i = %eval(&i -1); /*no duplicat found, write output statement*/ %else %do; userID = "&userID"; output; %end; /*add mewest ID to macro variable for duplicate checking*/ %let used = %sysfunc(catx(&delim_space,%nrstr(%superq(used)),%nrstr(%superq(userID)))); /*%put used: &used;*/ /*%put UserID: &userID;*/ %end; run; %mend; %ran6;
... View more