Home > Back-end >  How exactly does call symput work - trying to create an iterator with help of call symput
How exactly does call symput work - trying to create an iterator with help of call symput

Time:11-04

I am writing the code that is modifying an array declared in previous data step. Since it is a new datastep old indexes won't work. I thought I could use an iterator with help of call symput function. I was trying assign 0 value for each MID_(i) array element where month < "i" so I came up with code:

data want;
set summary;
do i=1 to &MAX_MONTH.;
    call symputx('iterator',i);
    if MONTH < &iterator. then MID_&iterator. = 0;
end;run;

And it doesn't work. I was experimenting with the code to debug it and inserted a constant value instead of "i":

data want;
set summary;
do i=1 to &MAX_MONTH.;
    call symputx('iterator',7);
    if MONTH < &iterator. then MID_&iterator. = 0;
end;run;

To confuse me even more, this code only works once. When I change '7' for other number the result stays the same until I reset SAS and after that it will work with changed value, but still - only once.

What happens here? What am I not understanding? How do I create a working iterator?

CodePudding user response:

I would recommend sticking entirely with arrays and if your variables have a naming convention you don't need anything else.

I don't have your data but I wonder if a simplification like this could work as well.

data want;
    set summary;
    array mid_[*] mid_:;

    do i=1 to month-1;
         MID_[i] = 0;
    end;
run;

CodePudding user response:

The macro processor does its work converting the macro expressions into text first. So &MAX_MONTH and &iterator have already been replaced by their values before SAS even begins to compile the data step, and definitely before it has a chance to run either the CALL SYMPUTX() or the IF statement.

So if MAX_MONTH had a value of 12 and ITERATOR had a value of 7 then you ran this data step:

data want;
  set summary;
  do i=1 to 12;
    call symputx('iterator',i);
    if MONTH < 7 then MID_7 = 0;
  end;
run;

Which is the same as just running:

data want;
  set summary;
  if MONTH < 7 then MID_7 = 0;
  i=13;
run;
%let iterator=12;

The ARRAY statement is the data step method to use to reference a variable by its position in a list. So if you want to reference variables with names like MID_1, MID_2, etc then define an array and use an index into the array. You could still use your MAX_MONTH macro variable to define the set of variables to include in the array.

So perhaps you meant to run something like this:

data want;
  set summary;
  array mid_ [&max_month] ;
  do index=month 1 to dim(mid_);
    MID_[index] = 0;
  end;
  drop index;
run;

CodePudding user response:

symput and symputx create macro variables after the data step ends. The macro variables being created cannot be accessed within the same data step. Each time symput is called, the macro variable that will be output at the end is updated.

Per the call symput documentation:

You cannot use a macro variable reference to retrieve the value of a macro variable in the same program (or step) in which SYMPUT creates that macro variable and assigns it a value.

You must specify a step boundary statement to force the DATA step to execute before referencing a value in a global statement following the program (for example, a TITLE statement). The boundary could be a RUN statement or another DATA or PROC statement.

You do not need to use symput to achieve your goal. i is already iterating and you can use it if you create a new array of your mid_ variables.

data want;
    set summary;
    array mid_[&MAX_MONTH.];

    do i=1 to dim(mid_);
        if MONTH < i then MID_[i] = 0;
    end;
run;
  • Related