使用 do 循环以相反的顺序重命名 SAS 变量

rename SAS variables in reverse order using do loops

我有 10 个变量 (var1-var10),我需要在 SAS 中重命名 var10-var1。所以基本上我需要将 var10 重命名为 var1、var9 var2、var8 var3 等等。

这是我根据本文使用的代码,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;

我遇到的问题是它只将 var1 重命名为 var10,因此 do 循环中的最后一次迭代。

在此先感谢您的帮助!

艾米丽

您真的不需要这样做,您可以使用列表引用重命名变量,尤其是在它们已按顺序命名的情况下。

即:

rename var1-var10 = var10-var1;

这是一个证明这一点的测试:

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;

如果您出于某种原因确实需要手动执行此操作,那么您需要两个数组。一旦你分配了变量,你就失去了旧变量,所以你不能再访问它了。所以你需要某种临时数组来保存新值。

虽然 Reeza 的回答是正确的,但可能值得仔细研究一下为什么您的方法不起作用 - 这是另一种合理的方法,如果令人费解的话。

首先,您有一些小的语法问题,例如分号放错地方、句号放在错误的位置(它们 end 宏变量名称,而不是开始它们),以及缺少 运行 语句;我们将忽略这些并在更改代码时修复它们。

其次,你有两个嵌套循环,当你真的不想要它的时候。您不想为 i 的每次迭代执行 10 次内部代码(每次 j 的迭代一次)(总共 100 次);您想为 ij 的每次迭代执行一次内部代码。

让我们看看这个修复给我们带来了什么:

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();

好的,现在这更接近你想要的东西了;但你有问题,对吧?您丢失了后半部分的值(好吧,实际上是前半部分,因为您使用 %by -1),因为它们没有存储在单独的地方。

您可以通过在其中存放原始变量的临时转储区域来实现此目的,从而允许您同时更改值和访问原始变量。一种常见的基于数组的方法(而不是基于宏的方法)以这种方式工作。这是它在宏中的样子。

%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;

我们使用 coalesce() 其中 returns 第一个非缺失参数;对于前五次迭代,它使用 var&j.,但后五次迭代使用 _var&j.。除了使用此函数,您还可以只预填充变量。

不过,一个更好的选择是使用 rename,正如 Reeza 在上述答案中所做的那样,但此处提供的内容更像您的原始答案:

%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;

这是有效的,因为 rename 实际上并没有移动东西 - 它只是将 "please write this value out to _____ variable on output" 的值设置为不同的值。

这实际上是作者在链接论文中提出的建议,我怀疑您只是错过了 rename 位。这就是为什么你在整个事情之后有一个分号(因为它只是一个 rename 语句,所以只有一个 ; )而不是在每次迭代之后有单独的分号(因为你需要分配)。