BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
theponcer
Quartz | Level 8

I have a data table that needs to be adjusted. I have a separate table that includes the type of adjustment. Both tables contain ID and month fields. I believe I should be able to use a hash iterator to find the ID/month combo that needs to be adjusted, adjust any necessary fields, and then move to the next month within that ID that needs to be adjusted (if necessary). However, I am not sure how to code this because I am not familiar with using hash iterators. I realize I could do this code if all of the ID/Month/Adjustment combinations were in the hash table, but I am trying to use the hash iterator. I am thinking it would look something like this:

 

 

 

Rules         
1) If you Quit Your Job, you stop receiving your $1 paycheck in that month and all subsequent months
2) If you get a raise, you get a $1 boost to your paycheck for that month and all subsequent months
3) If you win the lottery, you get $1,000,000 in addition to your paycheck for that month only 

 

Have - Data Table  
IDNameMonthMoney
1BillyJan$1
1BillyFeb$1
1BillyMar$1
2WillyJan$1
2WillyFeb$1
2WillyMar$1
3JillyJan$1
3JillyFeb$1
3JillyMar$1

 

Have - Hash Table 
IDMonthAdjustment
1FebQuit Job
2JanGot a Raise
3MarWon the Lottery

 

Want   
IDNameMonthMoney
1BillyJan$1
1BillyFeb$0
1BillyMar$0
2WillyJan$2
2WillyFeb$2
2WillyMar$2
3JillyJan$1
3JillyFeb$1
3JillyMar$1,000,001

 

data start_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 1
1 Billy Mar 1
2 Willy Jan 1
2 Willy Feb 1
2 Willy Mar 1
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1
;
run;

data adj_data;
   input ID $1 Month $3-5 Adjustment $6-35;
   datalines;
1 Feb Quit Job
2 Jan Got a Raise
3 Mar Won the Lottery
;
run;

data end_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 0
1 Billy Mar 0
2 Willy Jan 2
2 Willy Feb 2
2 Willy Mar 2
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1000001
;
run;

*Rules
1) If you quit your job, you don't get a paycheck for subsequent months
2) If you get a raise, your paycheck increases by $1 for all subsequent months
3) If you win the lottery, you get a one time bonus of $1,000,000;

data end_data_test;
set start_data;
if 0 then set adj_data;
if _n_=1 then do;
	dcl hash adj(dataset:"adj_data");
		adj.definekey("ID","Month");
		adj.definedata("ID","Month","Adjustment");
		adj.definedone();
	declare hiter h("adj_data");
end;
h.first(); *find the first match on the adjustment record;
	if Adjustment = "Quit Job" then do
	Money = 0; *If it is the "Quit Job" adjustment, set the first observation's Money amount to 0;
		do while (adj.find()=0);
			h.next(); *Set all subsequent month's Money amounts to 0 for this ID;
			Money=0;
		end;
	end;
	else if Adjustment = "Got a Raise" then  do
	Money = Money+1;
		do while (adj.find()=0);
			h.next();
			Money=Money+1;
		end;
	end;
	else if Adjustment = "Won the Lottery" then 
	Money = Money+1000000;
	*Here is code for how I would do this if the hash table included adjustments for each
	ID/month combo;
/*rc_adj=adj.find();*/
/*if rc_adj=0 then do;*/
/*	if Adjustment = "Quit Job" then*/
/*	Money = 0;*/
/*	else if Adjustment = "Got a Raise" then */
/*	Money = Money+1;*/
/*	else if Adjustment = "Won the Lottery" then */
/*	Money = Money+1000000;*/
/*	end;*/
/*else Adjustment="";*/

run;
1 ACCEPTED SOLUTION

Accepted Solutions
ScottBass
Rhodochrosite | Level 12

For the example as you have posted, you don't need a hash iterator.  There is no need to iterate over the hash.

 

Try this:

 

options nocenter;

data start_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 1
1 Billy Mar 1
2 Willy Jan 1
2 Willy Feb 1
2 Willy Mar 1
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1
;
run;

data adj_data;
   input ID $1 Month $3-5 Adjustment $6-35;
   datalines;
1 Feb Quit Job
2 Jan Got a Raise
3 Mar Won the Lottery
;
run;

data end_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 0
1 Billy Mar 0
2 Willy Jan 2
2 Willy Feb 2
2 Willy Mar 2
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1000001
;
run;

data test;
   * set PDV order and attributes ;
   if 0 then set start_data adj_data;

   * note that data set columns have an implied retain, which is what we want here ;
   * retain adjustment;  * you can add this if you wish but it is redundant (comment out and see for yourself) ;
   if (_n_ = 1) then do;
      declare hash _h1 ( dataset: "adj_data ( keep=id month adjustment )" , hashexp: 16 , ordered: "N" );
      _h1.defineKey("id","month");
      _h1.defineData("adjustment");
      _h1.defineDone();
   end;
   set start_data;
   by id;
   if first.id then call missing(adjustment);  * required due to the implied (or explicit) retain ;
   _rc_h1 = _h1.find();
   select(adjustment);
      when('Quit Job')        money=0;
      when('Got a Raise')     money=money+1;
      when('Won the Lottery') money=money+1000000;
      otherwise;
   end;
run;

proc compare base=end_data comp=test;
run;

Please post your question as a self-contained data step in the form of "have" (source) and "want" (desired results).
I won't contribute to your post if I can't cut-and-paste your syntactically correct code into SAS.

View solution in original post

1 REPLY 1
ScottBass
Rhodochrosite | Level 12

For the example as you have posted, you don't need a hash iterator.  There is no need to iterate over the hash.

 

Try this:

 

options nocenter;

data start_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 1
1 Billy Mar 1
2 Willy Jan 1
2 Willy Feb 1
2 Willy Mar 1
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1
;
run;

data adj_data;
   input ID $1 Month $3-5 Adjustment $6-35;
   datalines;
1 Feb Quit Job
2 Jan Got a Raise
3 Mar Won the Lottery
;
run;

data end_data;
   input ID $1 Name $3-8 Month $9-11 Money 12-20;
   datalines;
1 Billy Jan 1
1 Billy Feb 0
1 Billy Mar 0
2 Willy Jan 2
2 Willy Feb 2
2 Willy Mar 2
3 Jilly Jan 1
3 Jilly Feb 1
3 Jilly Mar 1000001
;
run;

data test;
   * set PDV order and attributes ;
   if 0 then set start_data adj_data;

   * note that data set columns have an implied retain, which is what we want here ;
   * retain adjustment;  * you can add this if you wish but it is redundant (comment out and see for yourself) ;
   if (_n_ = 1) then do;
      declare hash _h1 ( dataset: "adj_data ( keep=id month adjustment )" , hashexp: 16 , ordered: "N" );
      _h1.defineKey("id","month");
      _h1.defineData("adjustment");
      _h1.defineDone();
   end;
   set start_data;
   by id;
   if first.id then call missing(adjustment);  * required due to the implied (or explicit) retain ;
   _rc_h1 = _h1.find();
   select(adjustment);
      when('Quit Job')        money=0;
      when('Got a Raise')     money=money+1;
      when('Won the Lottery') money=money+1000000;
      otherwise;
   end;
run;

proc compare base=end_data comp=test;
run;

Please post your question as a self-contained data step in the form of "have" (source) and "want" (desired results).
I won't contribute to your post if I can't cut-and-paste your syntactically correct code into SAS.

hackathon24-white-horiz.png

The 2025 SAS Hackathon has begun!

It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.

Latest Updates

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 1 reply
  • 699 views
  • 2 likes
  • 2 in conversation