BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
rbettinger
Pyrite | Level 9

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?

1 ACCEPTED SOLUTION

Accepted Solutions
Rick_SAS
SAS Super FREQ

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.

View solution in original post

2 REPLIES 2
Rick_SAS
SAS Super FREQ

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.

rbettinger
Pyrite | Level 9

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?

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

Multiple Linear Regression in SAS

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.

From The DO Loop
Want more? Visit our blog for more articles like these.
Discussion stats
  • 2 replies
  • 660 views
  • 0 likes
  • 2 in conversation