BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Reeza
Super User
Post your code using the code button. It makes it easier to read and follow and prevents issues when copying and pasting your code from HTML to an editor.
Tom
Super User Tom
Super User

What is it that you want out of that?  Why are you doing all of that crazy macro stuff?

https://forum.wordreference.com/threads/idiom-for-doing-something-simple-in-a-lengthier-way.3366230/

 

%let vars=a b c;

data all;
  set a b;
  keep &vars;
run;

proc distance data=all out=Dist(keep=Dist1 rename=Dist1=d) method=Euclid;
  var interval(&vars);
run;

data want;
  set b;
  set dist(firstobs=2) ;
run;
Obs     a      b     c       d

 1      87    78    60    29.2916
 2      99    45    77    26.2679
 3     103    95    73    27.8927

 

alexgonzalez
Quartz | Level 8
Hi Tom,
First of all, thank you very much for your support and awesome considerations. I think that's not what I wanted. I needed to calculate difference between variables and macro variables. Feel free to check the solution proposed by Reeza. I tried and it's exactly what I needed.
Best regards, A.G.
Reeza
Super User

I definitely don't quite understand what you're trying to do overall, not sure why SET doesn't work as well? I feel like this could simplify your problem. However, assuming you want to stick with the approach identified, see a simplified solution below.

 

This would give the same solution as below - no macro logic besides the names and number of them needed which is trivial to get.

data final;
if _n_ =1 then set one;
set many_dist;


array diff(&number_vars) diff1-diff3;
array key(&number_vars) key:;
array _refs(&number_vars) &vars;

do i=1 to &number_vars.;
diff(i) = key(i) - _refs(i);
end;


run;

Some notes:

 

  1. Your &vars and var_list seem to be the same macro variable so not sure why you need to recreate it. 
  2. Creating the macro variables can be simplified massively, which I use here within the same data step as 'One'
  3. Rather than create multiple macro variables, I create a single one to use with all values in it.
data a;
	input id $ a b c d e;
	datalines;
001 100 70 85 86 94 
;

data b;
	input id $ a b c;
	datalines;
002 87 78 60 
003 99 45 77
004 103 95 73 
;

	%macro example (vars);
		%let number_vars = %sysfunc(countw(&vars)) ;

	data one;
		set a (keep=id &vars);

		/*One record only*/
		array _myvars(&number_vars) &vars.;
		call symputx('value_list', catx(' ', of _myvars(*)));
	run;

	data many;
		set b (keep=id &vars);

		/*Multiple records*/
	run;

	*Preparing dataset the calculation of the Euclidean distance;

	data all;
		set one many;
	run;

	*Calculating the Euclidean distance;

	proc distance data=all out=Dist (keep=dist1) method=Euclid;
		var interval(&vars);
	run;

	data dist;
		set dist;

		if _n_=1 then
			delete;
		rename dist1=d;
	run;

	*Matching each object with a distance value;

	data many_dist;
		merge many dist;
		*Renaming &vars before merging back with ‘One’;
		rename id=idcode;

		%do i=1 %to &number_vars.;
			rename %scan(&vars., &i.)=key_&i.;
		%end;
	run;

	data final;
		merge one many_dist;
		array diff(&number_vars) diff1-diff3;
		array key(&number_vars) key:;
		array _refs(&number_vars) _temporary_ (&value_list);

		do i=1 to &number_vars.;
			diff(i)=key(i) - _refs(i);
		end;
	run;

	data final2;
		if _n_=1 then
			set one;
		set many_dist;
		array diff(&number_vars) diff1-diff3;
		array key(&number_vars) key:;
		array _refs(&number_vars) &vars;

		do i=1 to &number_vars.;
			diff(i)=key(i) - _refs(i);
		end;
	run;

	proc datasets lib=work;
		delete one many: all z dist;
		run;
	%mend;

	%example (vars=a b c)

 

Reeza
Super User
	%macro example (vars);
		%let number_vars = %sysfunc(countw(&vars)) ;



	*Preparing dataset the calculation of the Euclidean distance;

	data all;
		set a (keep=id &vars)  b (keep=id &vars);
	run;

	*Calculating the Euclidean distance;

	proc distance data=all out=Dist (keep=dist1) method=Euclid;
		var interval(&vars);
	run;

	data dist;
		set dist;

		if _n_=1 then
			delete;
		rename dist1=d;
	run;

	*Matching each object with a distance value;

	data many_dist;
		merge b (keep = id &vars) dist;
		*Renaming &vars before merging back with ‘One’;
		rename id=idcode;

		%do i=1 %to &number_vars.;
			rename %scan(&vars., &i.)=key_&i.;
		%end;
	run;



	data final;
		if _n_=1 then
			set a (keep = id &vars);
			
		set many_dist;
		array diff(*) diff1-diff&number_vars;
		array key(*) key:;
		array _refs(*) &vars;

		do i=1 to dim(diff);
			diff(i)=key(i) - _refs(i);
		end;
	run;

	proc datasets lib=work;
		delete  many: all  dist;
		run;
	%mend;

	%example (vars=a b c)

This is the full simplified version that matches the results.

alexgonzalez
Quartz | Level 8
That worked Reeza. Thanks a lot for your great suggestions. I modified my macro it's much better now. I tried the code in the 'final' data set (with the other suggestions in the code). Very much appreciated.

SAS Innovate 2025: Call for Content

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!

Submit your idea!

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
  • 20 replies
  • 2241 views
  • 9 likes
  • 5 in conversation