DATA Step, Macro, Functions and more

Concatenate text values recursively

Reply
Contributor
Posts: 29

Concatenate text values recursively

Hi,

I have to concatenate the values of different macro variables and make a list of them.

The following code gives the value of Node as null/blank. It's not able to concatenate the null value of Node with another text

data test1;

length Node $5.;

Node = ' ';

Node = Node ||"A";

run;

Even if I use an initial value of Node as 'X'. It doesn't concatenate 'X' with 'A'. The following code gives the value of Node as X

data test1;

length Node $5.;

Node = 'X ';

Node = Node ||"A";

run;

    

I wanted to make just one variable Node and use it recursively (referring to its previous value each time), but since the above code wasnt working properly, I made separate variables each time and wrote the following code

options symbolgen mlogic;
options compress = yes;

%let C1 = A;
%let C2 = B;
%let C3 = C;
%let C4 = D;

%macro test;
data test;
length Node1 $5.;
Node1 = "&C1";
%do i = 2 %to 4;
/*%if &i = 1 %then %let j = &i;*/
/*%else*/ %let j = %eval(&i-1);
Node&i = Node&j || " &&C&i";
%end;
run;

%mend;

%test

The above does give an output value of Node4 as A   B C D but uses 3 spaces between A and B but 1 space (as used in the code) between B, C and D, etc.

Why dont the previous codes work? Why does the above code give 3 spaces between A and B.

Please advise!

PROC Star
Posts: 7,474

Re: Concatenate text values recursively

Posted in reply to varunnakra

You have to account for leading and trailing blanks and the fact that char fields are right filled with blanks.  How about something like:

data test1;

length Node $5.;

Node = ' ';

Node = compbl(Node) ||"A";

run;

data test1;

length Node $5.;

Node = 'X ';

Node = compbl(Node)||"A";

run;

   

%let C1 = A;

%let C2 = B;

%let C3 = C;

%let C4 = D;

%macro test;

data test;

length Node1 $5.;

Node1 = "&C1";

%do i = 2 %to 4;

/*%if &i = 1 %then %let j = &i;*/

/*%else*/ %let j = %eval(&i-1);

Node&i = compbl(Node&j) || " &&C&i";

%end;

run;

%mend;

%test

Regular Contributor
Posts: 191

Re: Concatenate text values recursively

Posted in reply to varunnakra

Start using the "cat"-functions, really useful....:-)

options symbolgen mlogic;
options compress = yes;

%let C1 = A;
%let C2 = B;
%let C3 = C;
%let C4 = D;


%macro test;
data test;
length Node1 $5.;
Node1 = "&C1";
Nodes1 = "&C1";
%do i = 2 %to 4;
/*%if &i = 1 %then %let j = &i;*/
/*%else*/ %let j = %eval(&i-1);
Node&i =catx(' ',Node&j,"&&C&i");
Nodes&i =cats(Nodes&j,"&&C&i");
%end;
run;

%mend;

%test

//Fredrik

Super User
Posts: 5,505

Re: Concatenate text values recursively

Posted in reply to varunnakra

You have some viable solutions posted.  I'm going to focus more on your final question:  Why?

This combination of statements assigns a 5-character value to NODE:

length node $ 5;

node='X';

SAS is storing "X" plus four additional blanks.

Now this expression is generating six characters:

node = node || 'A';

To the right of the equal sign is "X" then four blanks, then "A".  Since NODE is already defined as 5 characters long by the LENGTH statement, there is only room to store the first five characters of the assigned value.  So "A" cannot be added, and it looks like your statement does nothing.

As has been suggested, functions will handle the extra blanks, such as:

node = catx(' ', node, 'A');

Good luck.


Contributor
Posts: 29

Re: Concatenate text values recursively

Posted in reply to Astounding

Thanks a lot everyone for the insights Smiley Happy

Occasional Contributor
Posts: 15

Re: Concatenate text values recursively

Posted in reply to varunnakra

I was able to get the code to work by adding a trim statement:

data test1;

length Node $5.;

Node = ' ';

Node = trim(Node) ||"A";

Node = trim(Node) ||"B";

Node = trim(Node) ||"C";

Node = trim(Node) ||"D";

Node = trim(Node) ||"E";

run;

Respected Advisor
Posts: 3,156

Re: Concatenate text values recursively

Well, if you look closer, you will find out that Trim() will only remove those trailing blanks, as a result, you will NOT get 'ABCDE', instead, you are only getting ' ABCD', as trim() will generate a character of length at least 1. Here, strip() or compress() will be better options for your purpose, otherwise, you will have to use the combination of trim() and left() to do the same: trim(left()).

HTH,

Haikuo

Update: trim() will work if you modify the first concatenate statement: Node = "A" ||trim(Node);  That will safely put 'blanks', if there are, at the end, so trim() can take care of it.

Ask a Question
Discussion stats
  • 6 replies
  • 906 views
  • 3 likes
  • 6 in conversation