BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
turcay
Lapis Lazuli | Level 10

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

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

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)));

View solution in original post

19 REPLIES 19
ballardw
Super User

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;
turcay
Lapis Lazuli | Level 10

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.

RW9
Diamond | Level 26 RW9
Diamond | Level 26

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).

turcay
Lapis Lazuli | Level 10

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

 

 

ballardw
Super User

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.

turcay
Lapis Lazuli | Level 10

Thank you very much for your detailed explanations @ballardw

Quentin
Super User

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

BASUG is hosting free webinars Next up: Jane Eslinger presenting PROC REPORT and the ODS EXCEL destination on Mar 27 at noon ET. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
RW9
Diamond | Level 26 RW9
Diamond | Level 26

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.

 

turcay
Lapis Lazuli | Level 10

Thank you very much for detailed information @RW9,

 

I will consider your explanations, thanks again 🙂

slchen
Lapis Lazuli | Level 10

This is what you want?

 

%Let Variables=Variable1 Variable2 Variable3 Variable4 Variable5;
Data want;
VariablesP=prxchange('s/(\S+)/P$1/',-1,"&variables");
Run;

Cynthia_sas
SAS Super FREQ

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:

use_tranwrd.png

cynthia

turcay
Lapis Lazuli | Level 10

@Cynthia_sas,

 

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

Cynthia_sas
SAS Super FREQ

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:two_transform.png

 

  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

turcay
Lapis Lazuli | Level 10

@Cynthia_sas,

 

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

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 19 replies
  • 4954 views
  • 14 likes
  • 8 in conversation