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

时间:2017-11-27 17:01:05

标签: sas rename sas-macro 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循环中的最后一次迭代。

提前感谢您的帮助!

Emily

2 个答案:

答案 0 :(得分:2)

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

即:

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;

如果由于某种原因需要手动执行,那么您需要两个数组。一旦分配了变量,就丢失了旧变量,因此您无法再访问它。所以你需要某种临时数组来保存新值。

答案 1 :(得分:1)

虽然Reeza的回答是正确的,但可能值得一提的是为什么你的方法不起作用 - 这是另一种合理的,如果是错综复杂的方式。

首先,你有一些小的语法问题,例如错误的分号,错误位置的句点(他们结束宏变量名,不开始它们),以及缺少运行语句;我们会在更改代码时忽略这些并修复它们。

其次,你有两个嵌套循环,当你不是真的想要那个。对于j的每次迭代,您不希望对内部代码执行10次(i每次迭代一次)(总共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()返回第一个非缺失参数;对于前五次迭代,它使用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实际上并没有移动东西 - 它只是设置&#34的值;请将此值写入输出的_____变量"不同的东西。

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