3
votes

I have 10 variables (var1-var10), which I need to rename var10-var1 in SAS. So basically I need var10 to be renamed var1, var9 var2, var8 var3, and so on.

This is the code that I used based on this paper, http://analytics.ncsu.edu/sesug/2005/PS06_05.PDF:

%macro new;

    data temp_one;
        set temp;

        %do i=10 %to 1 %by -1;
            %do j=1 %to 10 %by 1;
                var.&i=var.&j
            %end;
        %end;
        ;
%mend new;

%new;

The problem I'm having is that it only renames var1 as var10, so the last iteration in the do-loop.

Thanks in advance for any help!

Emily

2
I wonder why the downvote? This is a quite high quality question; it's fairly basic, but it has all of the elements we look for in a good question - detailed code to reproduce, explicit statement of the incorrect behavior, and specificity.Joe
If you just want to rename variables without creating a new copy of the dataset, use proc datasets to do this, using the rename statement from reeza's answer.user667489

2 Answers

2
votes

You really don't need to do that, you can rename variable with list references, especially if they've been named sequentially.

ie:

rename var1-var10 = var10-var1;

Here's a test that demonstrates this:

data check;
    array var(10) var1-var10 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    output;
run;

data want;
    set check;
    rename var1-var10 = var10-var1;
run;

If you do need to do it manually for some reason, then you need two arrays. Once you've assigned the variable you've lost the old variable so you can't access it anymore. So you need some sort of temporary array to hold the new values.

1
votes

While Reeza's answer is correct, it's probably worth going through why your method didn't work - which is another reasonable, if convoluted, way to do it.

First off, you have some minor syntax issues, such as a misplaced semicolon, periods in the wrong places (They end macro variable names, not begin them), and a missing run statement; we'll ignore those and fix them as we change the code.

Second, you have two nested loops, when you don't really want that. You don't want to do the inner code 10 times (once per iteration of j) for each iteration of i (so 100 times total); you want to do the inner code once for each iteration of both i and j.

Let's see what this fix, then, gives us:

data temp;
  array var[10];
  do _n_ = 1 to 15;
    do _i = 1 to 10;
      var[_i] = _i;
    end;
    output;
  end;
  drop _i;

run;

%macro new();

    data temp_one;
        set temp;

        %do i=10 %to 1 %by -1;
            %let j = %eval(11-&i.);
            var&i.=var&j.;
        %end;
    run;

%mend new;

%new();

Okay, so this now does something closer to what you want; but you have an issue, right? You lose the values for the second half (well, really the first half since you use %by -1) since they're not stored in a separate place.

You could do this by having a temporary dumping area where you stage the original variables, allowing you to simultaneously change the values and access the original. A common array-based method (rather than macro based) works this way. Here's how it would look like in a macro.

%macro new();

    data temp_one;
        set temp;

        %do i=10 %to 1 %by -1;
            %let j = %eval(11-&i.);
            _var&i. = var&i.;
            var&i.=coalesce(_var&j., var&j.);
        %end;
        drop _:;
    run;

%mend new;

We use coalesce() which returns the first nonmissing argument; for the first five iterations it uses var&j. but the second five iterations use _var&j. instead. Rather than use this function you could also just prepopulate the variable.

A much better option though is to use rename, as Reeza does in the above answer, but presented here with something more like your original answer:

%macro new();

    data temp_one;
        set temp;
        rename
        %do i=10 %to 1 %by -1;
            %let j = %eval(11-&i.);
            var&i.=var&j.
        %end;
        ;
    run;

%mend new;

This works because rename does not actually move things around - it just sets the value of "please write this value out to _____ variable on output" to something different.

This is actually what the author in the linked paper proposes, and I suspect you just missed the rename bit. That's why you have the single semicolon after the whole thing (since it's just one rename statement, so just one ; ) rather than individual semicolons after each iteration (as you'd need with assignment).