An Introduction to the SAS Hash Iterator
I have written quite a few posts about the SAS hash object. However, none of them have mentioned the hash iterator object. Until today. This post will serve as a brief introduction to the hash iterator object. I will show you how to create the iterator object and link it to a hash object. Furthermore, I will show you an example or two of how to use it. Finally, I will write a few lines about how to think of the iterator object. It can be a bit abstract at first.
A Basic Introduction
The hash iterator object is an object that you link to a hash object in SAS. The iterator object can traverse the hash object forward or backward. It can start from either the logical first/last item or at the first item in a key group and move forward or backward from there. What separates the iterator object from traditional hash object methods is that it can cross key boundaries.
Just as with the hash object, we use dot notation and call methods on the iterator object. There are not as many iterator methods as traditional hash object methods. However, they have one thing in common: They all copy data from the hash object to the PDV. The iterator object can not hold any data. You can think of the iterator object as a construct that can point to and run through individual elements in the hash object and copy their data portions into the PDV.
Declaring the Iterator Object
Just as with a Hash Object, we must declare the iterator object before we use it. We use the Declare Statement to create an iterator object. In the declare statement we use the hiter keyword to specify that we create an iterator object, not a hash object. The hiter keyword requires a single argument; the hash object we want to link it to.
In the code below, I have written a very simple example of you to create a hash iterator object and link it to a hash object. Be aware that though the first way to do so is the most common, you can separate the declaration part and the instantiation part. I have written the equivalent statements and commented them out for demonstration. This concept is similar to what I explain in the post Declare and Instantiate the SAS Hash Object.
data _null_; key=.; data=.; declare hash h(); h.definekey('key'); h.definedata('data'); h.definedone(); declare hiter hi('h'); /* Equivalent to declare hiter hi; hi = _NEW_ hiter('h'); */ run;
Notice, that if you do not specify an existing hash object in the parenthesis, you will get an error. Any valid iterator instance must be linked to a hash object instance.
Iterate Through a Hash Object
Above, we see how to declare the iterator object and link it to a hash object. Next, let us see how to use it with a simple example. In the first part of the code, I simply do as above. I declare a hash object h. Then, I declare an iterator object, hi, and link it to the hash object h. Next, I fill the hash object with key and data values. Next, let us use the iterator object to run through the entire hash object. Just as with the hash object, we use methods to call actions on the object. In this case, I want to start with the logical first element in the hash object and go through the entire object. Notice, I use the ordered:Y argument tag in the declaration of the hash object. This makes the smallest key value the first logical element.
In the second do loop, I iterate through the entire SAS hash object h. Initially, I call the First() Method and assign the returned value to the variable rc. Just as any other object method, it returns 0 for success and a non-zero value for failure. In this case, success means that a logical first element exists in the hash object and that the data values were successfully copied into the PDV. Inside the loop, I call the Next() Method and assign the return value to rc. Not surprisingly, the Next() Method finds the next element in the hash object and copies the data value into the PDV. I design the loop as a Do While Loop and keep iterating through the hash object while the method calls returns zero values. When they do not, the loop terminates and there are no more elements to go through.
data _null_; declare hash h(ordered:'Y'); h.definekey('key'); h.definedata('key', 'data'); h.definedone(); declare hiter hi('h'); do key=1 to 4; data=key*2; h.add(); end; do rc=hi.first() by 0 while (rc=0); put key= data=; rc=hi.next(); end; /* Backwards */ do rc=hi.last() by 0 while (rc=0); put key= data=; rc=hi.prev(); end; run;
In this example, I put the values of key and data in the log, so you can see what values are copied from the hash object to the PDV. I.e. which elements the iterator object runs through and in what order. In the last do loop, I use the exact same logic, though backward.
In this post, I have introduced the SAS hash iterator object. I have briefly introduced the basic concepts of what, where and why. Next, we have seen how to declare and instantiate the obejct. Finally, I demonstrate how to use the iterator to traverse an entire hash object. I have not focused too much on the individual iterator methods. I will save that for the blog post The 5 Hash Iterator Object Methods in SAS.
If you want to learn more about the SAS hash object and iterator object, read the book Data Management Solutions Using SAS Hash Table Operations by Don Henderson and Paul Dorfman. Furthermore, you should consult the SAS documentation page Using the Hash Iterator Object.
You can download the entire code from this post here.