Question 1: I want to append an item to a list. The code works in one case but not in another, and I can't figure out why the failure occurs. Here is the program:
proc iml ; package load listutil ;
L = [ #'Input'=[] ] ;
var = [ #'var1'='var1' ] ;
L$'Input' = L$'Input' || var ;
call struct( L ) ;
MF = [ #'MF'='MF' ] ;
L$'Input'$'var1' = L$'Input'$'var1' || MF ;
call struct( L ) ;
quit ;
The structure is the same in each case: create a list item, then append it to the parent list. The first case has one level, and the second has two levels. Why does the second case fail when the first case works? What is changed by adding another level?
Question 2: If I want to build a list inside of a module with a varying item name under program control, how do I do this? Here is my example:
proc iml ; package load listutil ;
L = [ #'Input'=[] ] ;
var = 'var1' ;
L$'Input' = L$'Input' || [ var = 'variable item name' ] ;
call struct( L ) ;
quit ;
While the code executes correctly, the item name is 'Input[1]' instead of 'var1' and the value is 0 instead of 'variable item name' so I know that the variable 'var' is not resolved into 'var1' as the item name. How do I use a variable instead of a literal to allow me the flexibility that I want?
A1. In the first example, L$'Input' and var are both lists. So
L$'Input' || var ;
is the concatenation of two lists.
In the second example, L$'Input'$'var1' is a character string and MF is a list. The operation
L$'Input'$'var1' || MF
is undefined. To resolve the issue, either enclose the left-hand argument in square brackets to make it a list, or use the $ operator to extract the character value from the right-hand argument.
A2: The documentation for associative arrays says:
"Specify the name of an item by prefixing it with the '#' symbol. You can specify the name as a character literal or as a quoted string."
Notice that it does not say that you can specify the name as the value of a character matrix, which seems to be what you are trying to do.
There are two ways to deal with this issue:
1. You can use the LISTSETNAME function to assign a name after you create the list.
2. You can use SAS to write SAS code, so you can circumvent this limitation by using macro or CALL EXECUTE. If you choose this option, I suggest that you use CALL SYMPUT for this.
A1. In the first example, L$'Input' and var are both lists. So
L$'Input' || var ;
is the concatenation of two lists.
In the second example, L$'Input'$'var1' is a character string and MF is a list. The operation
L$'Input'$'var1' || MF
is undefined. To resolve the issue, either enclose the left-hand argument in square brackets to make it a list, or use the $ operator to extract the character value from the right-hand argument.
A2: The documentation for associative arrays says:
"Specify the name of an item by prefixing it with the '#' symbol. You can specify the name as a character literal or as a quoted string."
Notice that it does not say that you can specify the name as the value of a character matrix, which seems to be what you are trying to do.
There are two ways to deal with this issue:
1. You can use the LISTSETNAME function to assign a name after you create the list.
2. You can use SAS to write SAS code, so you can circumvent this limitation by using macro or CALL EXECUTE. If you choose this option, I suggest that you use CALL SYMPUT for this.
I had never thought to use SAS/MACRO within SAS/IML, but the CALL SYMPUT suggestion works just fine! Thank you very much, Rick.
Here is my code. The first example does not use CALL SYMPUT, and the second one does, giving me the flexibility that I need.
proc iml ; package load listutil ;
print 'this code does not use CALL SYMPUT' ;
L = [ #'Input' = ] ;
call struct(L) ; call listprint(L) ;
L$([ 'Input' ]) = L$([ 'Input' ]) || [ #'Var1' = [ #a=, #b=, #c=]] ;
call struct(L) ; call listprint(L) ;
L$([ 'Input', 'Var1' ]) = L$([ 'Input', 'Var1' ]) || [ #'MF1'=[ #mf1=, #mf2=, #mf3=, #mf4=]] ;
call struct(L) ; call listprint(L$'Input'$'Var1') ;
L_I_V = L$'Input'$'Var1'$'MF1' ; call struct(L_I_V ) ;
print 'this code uses CALL SYMPUT' ;
call symput( 'VAR', "Var1" ) ;
call symput( 'MF' , 'MF1' ) ;
L= [ #'Input'= ] ; call struct(L) ;
L$([ 'Input' ]) = L$([ 'Input' ]) || [ #"&VAR" = [ #a=, #b=, #c=]] ;
call struct(L) ;
L_I = L$'Input'$"&VAR" ; call struct(L_I ) ;
L$([ 'Input', "&VAR" ]) = L$([ 'Input', "&VAR" ]) || [ #"&MF"=[ #mf1=, #mf2=, #mf3=, #mf4=]] ;
call struct(L) ;
L_I_V = L$'Input'$"&VAR"$"&MF" ; call struct(L_I_V ) ;
quit ;
I noticed that the call struct( L ) command does not produce all of the sublist and items of the list L. How can I tell the struct() module to print the entire structure of the list? Are the parameters stored somewhere and can I use a list function to change them?
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 to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.
Find more tutorials on the SAS Users YouTube channel.