@lydiawawa:
There exists a fairly widely spread illusion that one needs to know how to use the hash object only when one has a lot of data to process. Surely under many circumstances hash tables can speed things up quite a bit - for example, by making it unnecessary to sort large files when data need to be combined or aggregated. However, the main strength of the hash object in general is that it is an extremely flexible and convenient tool for dynamic programming, frequently lending itself to accomplishing in one step and/or single pass what otherwise would require several and doing it using simpler and more straightforward logic to boot.
The task you've posted in this thread is a good illustration. Imagine that your data are unsorted and look at the hash program doing what you want:
data have_unsorted ;
input id $ date $ ;
cards ;
2 1/3/2006
2 1/1/2005
2 1/1/2005
2 1/1/2005
2 1/2/2005
1 1/1/2001
1 1/2/2002
2 1/2/2005
2 1/3/2006
1 1/2/2002
1 1/2/2003
1 1/2/2003
1 1/1/2001
;
run ;
data want_unsorted ;
if _n_ = 1 then do ;
dcl hash h () ;
h.definekey ("id", "date") ;
h.definedata ("count") ;
h.definedone () ;
end ;
set have_unsorted ;
if h.find() ne 0 then count = 1 ;
else count + 1 ;
h.replace() ;
run ;
If you're unfamiliar with the hash object, it may look Greek to you, and yet its logic it exceedingly simple. Namely, for each record:
If a key-value (id,date) is not in the table yet, assign count=1 and store it in the table. Output count=1.
Otherwise, look in the table and see what count is there for this (id,date). Add 1 to that count value and store the result back in the table for this (id,date) overwriting the previous value of count there. Output the new value of count.
It's that simple. The hash table just keeps track of all previous counts for every (id,date) key-value encountered thus far. And because it automatically grows by 1 item every time a new (id,date) is seen, there's no need to pre-process the input to size it up at compile time - as it would be necessary, for example, if an array were used as the count-tracking table instead. Furthermore, when you search the table for the current record's (id,date) value to find what the previous value of count has been, this act of lookup takes the same time regardless of how many items have been stored in the table (say, ten or a million), as this is one of the hash object's properties. If you're interested, a brief compendium on things of this nature can be found here (penned by @DonH and yours truly):
http://support.sas.com/resources/papers/proceedings17/0821-2017.pdf
Kind regards
Paul Dorfman
... View more