Hello everyone,
I try to concatenate my macro variables whole values with "P" character value.
I tried the following code. The following code got an error and also I did not reach my aim.
Log seems like this ->PVariable1 Variable2 Variable3 Variable4 Variable5
But I want to see the variables like this ->PVariable1 PVariable2 PVariable3 PVariable4 PVariable5.
How can I concatenate my macro variables values with "P" value.
%Let Variables=Variable1 Variable2 Variable3 Variable4 Variable5;
Data Want;
VariablesP=%Sysfunc(Catx(%Str(),%Str(P),&Variables));
Run;
Can somebody help me, please?
Thank you
You don't want to use CATX(), you want to use TRANWRD(). In general there is not much use for the CAT... function in macro code.
If you want to add the prefix P to every value in a space delimited list then just prefix the first word and change the delimites to include the prefix for the following words.
%Let Variables=Variable1 Variable2 Variable3 Variable4 Variable5;
%let newlist=P%sysfunc(tranwrd(&variables,%str( ),%str( P)));
You probably will also want to make sure your list is neat and does not have multiple spaces between words. So add this line before the other.
%Let Variables=%sysfunc(compbl(&variables));
Or nest the call to COMPBL() into the call to TRANWRD().
%let newlist=P%sysfunc(tranwrd(%sysfunc(compbl(&variables)),%str( ),%str( P)));
Good things seldom come from using macro functions in a datastep. Most uses are from a misunderstanding of what you are attempting to do.
This may accomplish what you are attempting. However the datastep variable name Variables may need to be longer than 200 characters depending on how many values you are placing in the macro variable. You need to ensure it is at least as long as the macro variable +2*number of words in that macro variable.
data want;
length variables $ 200 _temp_ $ 32;
do _i_ = 1 to countw("&variables");
_temp_ = cats("P", scan("&variables",_i_));
variables = catx(' ',variables,_temp_);
end;
drop _i_ _temp_;
run;
Thank you very much @ballardw,
You are right, I told myself incorrect. I want to get "VariablesP" variable as a Macro variable.
I mean that &VariablesP should include ->PVariable1 PVariable2 PVariable3 PVariable4 PVariable5
Is it possible to do?
Thank you and sorry for missunderstanding.
The question I would ask is why? Seems like your just making work for yourself. In your Base SAS code you can use groups of variables with a specified prefix without needing to specify each of them:
catx(' ',of variable:);
For example. Why create a macro variable with a list of X characters where only a number is different? If you need to specify part of it:
%let v=variable; data want; set have; result1=catx(' ',of &v.:); result2=catx(' ',of P&v.:); run;
This will create two variables - the first holds all variableX values concatenated, the second all PvariableX variables concatenated. Much easier to unserstand and maintain (for instance if the number of variables changes).
Thank you very much @RW9 for trying to help me.
I just didn't exactly understand your response.
I need macro variable because I will use in my future steps in my project. I just want to get this values being a macro variable. I could not understand your sample exacty, it brings an error because I did not have "Have" Data set. If I create this variable in data set I cannot use without its data set. I need a macro variable because I want to use everywhere what I want without depending on any data set.
Is it possible to get these values into Macro Variable? ->PVariable1 PVariable2 PVariable3 PVariable4 PVariable5
Thank you
Here is a generic macro I wrote awhile back that takes each "word" in the first parameter (a) and appends each "word" of the second parameter to it. There should be NO quotes, commas or parantheses within either parameter and presence of other special characters may be problematic.
%macro mixer (a=, b=);
/* a and b are Space delimited lists of words.
Think of a as the base of a varible and b as
a suffix
*/
%local a b str acount bcount i j aword bword;
%let str=;
%let Acount = %sysfunc(countw(&a));
%let Bcount = %sysfunc(countw(&b));
%do i= 1 %to &acount;
%let Aword= %scan(&a,&i);
%do j=1 %to &bcount;
%let Bword= %scan(&b,&j);
%let str= &str &aword.&bword;
%end;
%end;
&str
%mend;
%let variables = var1 var2 var3;
%let PVariables = %mixer(a=P, b=&variables);
%put &Pvariables;
With an example of assigning the values to your specific macro variable.
Not this could be used directly in a procedure:
Proc print;
vars %mixer(a=P, b=&variables);
run;
assuming the resulting variable names are in the data set. You may not need to create the macro variable unless you want to use it in many places.
I wrote this so I could reference the names created by procedures such as summary with the autoname option when used with multiple variables but has had other uses.
Thank you very much for your detailed explanations @ballardw
I'm a big fan of Richard DeVenezia's utility macro %seplist. It allows you to manipulate the items in a list, adding prefixes, suffixes, delimiters, etc.
Examples like:
124 %Let Variables=Variable1 Variable2 Variable3 Variable4 Variable5; 125 %put %seplist(&variables,dlm=%str( ),prefix=P); PVariable1 PVariable2 PVariable3 PVariable4 PVariable5 126 %put %seplist(&variables,dlm=%str(,),prefix=P); PVariable1,PVariable2,PVariable3,PVariable4,PVariable5 127 %put %seplist(&variables,dlm=%str( ),nest=QQ); "Variable1" "Variable2" "Variable3" "Variable4" "Variable5"
He has posted the macro at:
http://www.devenezia.com/downloads/sas/macros/index.php?m=seplist
Yes, it will give an error, that was an example. The concept is to use the functionality of Base SAS, rather than trying to force it in yourself with macro code. Lets examine, your list consists of:
variableX
So variable is the prefix used in your first set of variables, and Pvariable is the second copy of this. Base SAS provides functions and processes to deal with sets of variables which have the same prefix, one of these if prefix:, the colon states use all with prefix. Thus the only thing we need to know from your list of variables is the prefix, and we have all the information to deal with all prefix variables as well as P+prefix variables.
%let prefix=variable;
/* The above is all the information I need to process all variables with -variable- as the prefix
and also -Pvariable- */
data have;
variable1=123; variable2=34; variable3=67;
pvariable=23; pvariable=90; pvariable=123;
run;
data want; set have; result1=catx(' ',of &prefix.:);
/* in the above example my code resolves to:
result1=catx(' ',of variable:);
This tells SAS to concatenate all variables which have "variable" followed by an incrementor */
result2=catx(' ',of P&v.:);
/* in the above example my code resolves to:
result2=catx(' ',of Pvariable:);
This tells SAS to concatenate all variables which have P - from the code, followed by variables
which comes from the macro resolution, followed by an incrementor */ run;
The result of the above code (should - I haven't run it as not at work any more) is a dataset called want where variable1-3 is concatenated into result1, and pvariable1-3 is concatenated into result2. At no point in the code do i specify any number of the variables, I let Base SAS do that for me. The code will expand/shrink for any amount of variableX or pvariableX, whereas in your scenario you would then need to edit the macro value to add new variables or remove them. Note that this is an example - yu could use other functions, create arrays etc. using the same : modifier.
Its also not the only way in which you can work with Base SAS to achieve an end result, without having to resort to messy, hard to maintain macro code. Another example would be to alter the structure of the data, so that you have a parameter/result going down the page rather than across - this is called a normalised dataset and is pretty much used around - CDISC for instance, most databases.
So instead of:
VARIABLE1 VARIABLE2 VARIABLE3 PVARIABLE1 PVARIABLE2 PVARIABLE3
123 456 234 76 89 234
Normalise the data to:
VAR RESULT
VARIABLE1 123
VARIABLE2 456
VARIABLE3 234
PVARIABLE1 76
PVARIABLE2 89
...
With this scenario you can simply apply calculations/transformations to a column called RESULT without caring how many rows there are as it will apply to all (or you could where clause it) - note you don't have to use those variables names. You can always transpose the data up if you need it in the previous example for a report or something, so make your programming life easier.
Thank you very much for detailed information @RW9,
I will consider your explanations, thanks again 🙂
This is what you want?
%Let Variables=Variable1 Variable2 Variable3 Variable4 Variable5;
Data want;
VariablesP=prxchange('s/(\S+)/P$1/',-1,"&variables");
Run;
Hi:
And, if all you need is another macro variable, you do not need a DATA step program, you can do it with %SYSFUNC and TRANWRD:
cynthia
Thank you very much. You understand my question right but I want to investigate one more thing, I guess I skipped to tell. My "Variables" macro varible can include different values such as -> %Let Variables=Variable1 Column2 Variable3 Column4 Variable5;
If I get foregoing macro variable, the following code cannot add "P" values at the beginning of "Column2" and "Column4" values.
I mean that the values of macro variable can change, so can you help me to resolve this step, please?
%Let Variables=Variable1 Column Variable3 Column Variable5;
/* */
%Let VariablesP=%Sysfunc(TranWrd(&Variables,Variable,PVariable));
%Put PVar is &VariablesP;
Thank you
Hi:
It doesn't make sense to me that you have "Column" repeated twice when all your other tokens are numbered values:
%Let Variables=Variable1 Column Variable3 Column Variable5;
So I gave the variables the names Column2 and Column3, just to make them unique. Basically, you add the prefix to &Variables values and then you come back a second time using %SYSFUNC and TRANWRD and make the same change to the string 'Column' to PColumn, as shown below:
It is really just doing the transform in 2 steps and 2 lines of code and making sure that the first time you use TRANWRD on &VARIABLES, but the second time you make the change to &VARIABLESP to make sure that you don't lose the first change.
cynthia
Sorry for writing double Column value instead of Column2 and Column4 and thank you for trying to help me.
I tried your sample as below, it works for Variable and Column values but what if the whole values were different. I mean that I won't know the input values, these are input values ->Variable1 Column2 Value3 Data4 Preffix5 so these values can change. For this reason I do not want to depend on some values, I want to build dynamic structure.
However, after I listened your advice about @slchen code, I got my desired result.. It brings PVariable1 PColumn2 PValue3 PData4 PPreffix5.
%Let Variables=Variable1 Column2 Value3 Data4 Preffix5;
/*Cynthia Zender*/
%Let VariablesP=%Sysfunc(TranWrd(&Variables,Variable,PVariable));
%Put PVar is &VariablesP;
%Let VariablesP=%Sysfunc(TranWrd(&VariablesP,Column,PColumn));
%Put PVar is &VariablesP;
/*Slchen*/
Data Want;
Call Symput("VariablesP",PrxChange("s/(\S+)/P$1/",-1,"&Variables"));
%Let VariablesPP=PrxChange("s/(\S+)/P$1/",-1,"&Variables");
Run;
%Put &VariablesP;
%Put &VariablesPP;
Thank you
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.