Lists are collections of objects. SAS/IML 14.2 supports lists as a way to store matrices, data tables, and other lists in a single object that you can pass to functions. SAS/IML lists automatically grow if you add new items to them and shrink if you remove items. You can also modify existing items. You can use indices to refer to items of a list, or you can assign names to the items to create a named list.
Create a list
You can create a list by using the ListCreate function. If you know how many items the list will contain, you can specify the list length when you create the list. You can then use the ListSetItem subroutine to assign a value to each item:
proc iml; L = ListCreate(2); /* L is two-item list */ call ListSetItem(L, 1, 1:3); /* 1st item is 1x3 vector */ call ListSetItem(L, 2, {4 3, 2 1}); /* 2nd item is 2x2 matrix */ |
The arguments for the ListSetItem subroutine are list, index, and value, which is the same order that you use when you assign a value to a matrix element, such as A[2] = 5.
If you do not know how many items the list will contain, or if you later want to add additional items, you can use the ListAddItem subroutine to append new items to an existing list. The list will automatically grow to accommodate the new item:
X = {3 1 4, 2 5 3}; /* create a 2x3 matrix */ call ListAddItem(L, X); /* add 3rd item; list grows */ |
Notice that the syntax for the ListAddItem subroutine only requires the list and the value because the new item is always added to the end of the list. At this point, the list contains three items, as shown below:
Insert, modify, and delete list items
A convenient feature of SAS/IML lists is that they automatically resize. You can insert new items into any position in the list. You can also replace an existing item or delete an item. The following statements demonstrate modifying an existing list.
call ListInsertItem(L, 2, -1:1); /* insert new item before item 2; list grows */ call ListSetItem(L, 1, {A B, C D}); /* replace 1st item with 2x2 character matrix */ call ListDeleteItem(L, 3); /* delete 3rd item; list shrinks */ |
The arguments for the ListInsertItem subroutine are again list, index, and value. Inserting an item at position k means that the new item becomes the tth item and existing higher-indexed items are renumbered. (Conceptually, imagine some items "move to the right" to "make room" for the new item.) If you delete the item at position k, existing higher-indexed items are also renumbered. (Conceptually, items "move to the left.") After the previous sequence of operations, the list contains the following items:
Create named lists
In the previous section, the list acted like a dynamic array: it stored items that you could access by using indices such as 1, 2, and 3. For some applications, it makes more sense to name the list items and refer to the items by their names rather than their positions. This is similar to "structs" in some languages, where you can refer to members of a struct by name.
For example, suppose a teacher wants to store information about students in her classes. For each student, she might want to store the student's name, class, and test scores. The following statements create a SAS/IML list that has three items named "Name", "Class", and "Scores". The items are then assigned values:
Student = ListCreate({"Name" "Class" "Scores"}); /* create named list with 3 items */ call ListSetItem(Student, "Name", "Ron"); /* set "name" value for student */ call ListSetItem(Student, "Class", "Statistics"); /* set "class" value for student */ Tests = {100 97 94 100 100}; /* test scores */ call ListSetItem(Student, "Scores", Tests); /* set "scores" value for student */ |
Although you can still use positional indices to access list items ("Ron" is the first item, "Statistics" is the second item, ...), you can also use the name of items. For example, to extract the test scores into a SAS/IML matrix or vector, you can use the ListGetItem function, as follows:
s = ListGetItem(Student, "Scores"); /* get test scores from list */ |
Lists are for storing items, not for computing. You cannot add, subtract, or multiply lists. However, the example shows that you can extract an item into a matrix and subsequently perform algebraic operations on the matrix.
Lists of lists
Lists can contain sublists. In this way you can represent nested or hierarchical data. For example, the teacher might want to store information about several students. If information about each student is stored in a list, then she can use a list of lists to store information about multiple students.
The following statements create a list called All. The first student ("Ron") is added to the list, which means that the item is a copy of the Student list. Then information about a second student ("Karl") is stored in the Student list and copied into the All list as a second item. This process could continue until all students are stored in the list.
All = ListCreate(); /* empty list */ call ListAddItem(All, Student); /* add "Ron" to list */ call ListSetItem(Student, "Name", "Karl"); call ListSetItem(Student, "Class", "Calculus"); call ListSetItem(Student, "Scores", {90 92 84 70 80}); call ListAddItem(All, Student); /* add "Karl" to list */ |
At this point, the All list contains two items. Each item is a list that contains three items.
Summary
SAS/IML 14.2 supports lists, which are containers that store other objects. Lists dynamically grow or shrink as necessary. You can index items by their position in the list (using indices) or you can create a named list and reference items by their names. You can use built-in functions to extract items a list or add new items to a list. You can insert, delete, and modify list items. You can represent hierarchical data by using lists of lists. For more information about SAS/IML lists, see the SAS Global Forum paper "More Than Matrices" (Wicklin, 2017) or the chapter "Lists and Data Structures" in the SAS/IML documentation. The documentation shows how lists can be used to emulate other data structures, such as stacks, queues, and trees.
9 Comments
Is the IML trying to be object oriented language ?
I knew Java has such kind of data structure.
No. These are not classes that support members and methods. List are "containers" that make it easy to pack up related data into a single unit and pass it to and from functions. A simple application is an array of matrices.
I will mention, however, that IMLPlus has supported Java classes since the early 2000s, and some SAS customers use that feature.
Is there a way to replace columns for a table without extracting all the data into a matrix or array?
No, that feature is not implemented in SAS/IML 9.4M5.
Pingback: Video: Create and use lists and tables in SAS/IML - The DO Loop
Is there a way to save a list object to disk (memory) for later use, i.e. in a separate instance of SAS/IML than the one in which it was created?
That is a great question. Currently, the answer is no for PROC IML. However, you can do it in the iml action in SAS Viya. I will pass this suggestion on to the development team.
Pingback: Operations on lists in SAS/IML - The DO Loop
Pingback: Add an item to a sublist - The DO Loop