I'm trying to match keys 'A' and 'B' both to key 'C'. I wonder if this is doable in hash table.
Simplified version of this problem:
key: Location, Gender
Value: Pet
data dict; infile datalines; input Location$ Gender $ Pet $; datalines;
GreenBay M Dog
Madison F Badger Milwaukie B Cat ; run; data have; infile datalines; input Subject$ Location$ Gender$; datalines; 1 GreenBay M 2 Madison F
3 Milwaukie M
4 Milwaukie F ; run;
data want;
infile datalines;
input Subject$ Location$ Gender$ Pet$;
datalines;
1 GreenBay M Dog
2 Madison F Badger
3 Milwaukie M Cat
4 Milwaukie F Cat
;
run;
Using 'dict' dataset as hashtable, I want the result 'want' dataset.
Obviously, F and M in 'have' dataset should both match to B (means both) in dict dataset.
Can we do something to the hash table to make this happen?
I can solve this in some non-hashtable ways:
1. alter work.dict so that if we see a B, we output(copy) it into 2 rows with F and M
2. proc sql left join.
In reality, both 'have' dataset and 'dict' dataset have about 1000 rows so I really don't want to use the methods above.
Here is how I interpret your request. Obviously, you want M to match M and F to match F in your lookup. However, if a match if not found, you want both M and F to match B.
The code below first looks up in dict using the PDV "host" value. If a match is not found, we simply do a explicit lookup for "B".
Let me know if this works for you 🙂
data want(drop = rc);
if _N_ = 1 then do;
dcl hash h(dataset : 'dict');
h.definekey('Gender');
h.definedata('Pet');
h.definedone();
end;
set target;
if 0 then set dict;
if h.find() then rc = h.find(key : 'B');
run;
Result:
Subject Gender Pet 1 M CAT 2 F CAT
Shouldn't the variable Subject be the primary lookup variable here and not gender? Otherwise all obs in target would match all obs in dict where gender = "B"? I assume your actual data is a bit bigger than the posted 🙂
What if your dict table looks like this? What would your desired result look like?
data dict;
infile datalines;
input Subject $ Gender $ Pet $;
datalines;
1 B CAT
3 B DOG
;
You say you don't want to alter work.dict, and you probably don't want to make a copy either. What about a view?
data dict_view/view=dict_view;
set dict;
if Gender="B" then do;
Gender="M"; output;
Gender="F"; output;
end;
output;
run;
data try;
if 0 then set dict_view;
declare hash dict(dataset:"dict_view", multidata:"y");
rc= dict.defineKey("SUBJECT","Gender")
+dict.defineData("Pet")
+dict.defineDone();
/*...*/
run;
I cannot make heads or tails of what you are trying to do. But if you want both M and F to match to a hash key of B then you could create a format that maps M and F to B then use the formatted value as they in the hash.FIND() method call.
proc format ;
value $genderkey 'M','F'='B';
run;
...
rc=h.find(key: put(gender,$genderkey.));
...
The reply button should be below the right hand lower corner of the message.
Here is how I interpret your request. Obviously, you want M to match M and F to match F in your lookup. However, if a match if not found, you want both M and F to match B.
The code below first looks up in dict using the PDV "host" value. If a match is not found, we simply do a explicit lookup for "B".
Let me know if this works for you 🙂
data want(drop = rc);
if _N_ = 1 then do;
dcl hash h(dataset : 'dict');
h.definekey('Gender');
h.definedata('Pet');
h.definedone();
end;
set target;
if 0 then set dict;
if h.find() then rc = h.find(key : 'B');
run;
Result:
Subject Gender Pet 1 M CAT 2 F CAT
Sure thing 🙂
The Hash Object Find Method searches for a key value in the hash object and updates the data variables if the search is succesful.
The Find Method can be called either implicitly or explixitly.
The implicit call h.find() (notice there is nothing in the parentheses) searches using the value(s) in the PDV host variables. In this case we search for "M" and "F" respectively because they are in the PDV in obs 1 and 2.
The explixit call allows us to specify the key to search for directly in the parentheses, taking precedence over the PDV value.
Hope this makes sense.
Sorry you're having trouble with the website.
Is there a way for us to define the ordering and the equality of character values so we can alter the behavior of the HASH object or the MERGE statement? I'd say No, not in my experience have I encountered a method to make the characters B equate to F and M.
If there was a way to make B equal F and B equal M by changing a keymap you'd make F equal M.
I've coded using C++, there you can "overload the operators". Coding any special case you dream of Using '=', '<' and '>'. I know nothing of this existing in SAS.
Knowing computer science, there's probably a way, so asking the question is a worthy exercise. And I hope someone shows us how to do this here.
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.
Ready to level-up your skills? Choose your own adventure.