Arrays SAS-如何使用数组跳过循环中的某些列

Arrays SAS-如何使用数组跳过循环中的某些列,arrays,if-statement,sas,Arrays,If Statement,Sas,我有一个包含多个数字和字符列的数据集。大多数字符列都是简单的“是”或“否”问题,但有些不是。对于数字列,我觉得我有一个有效的解决方案。对于字符列,我尝试最小化它,但没有成功我想做并尝试的是一个循环,它指出当j=var4的列数时,使用大/小/IU替换。这个想法是,这将减少代码的“变量依赖性”,因为我可以在%let语句中更改var4的变量,并且代码的长度将更短 由于dim语句给出了数字或字符列的总数,我猜有一些语句给出了特定变量的列位置,我将用于secound循环。但是,我没有发现这样的说法 我的代

我有一个包含多个数字和字符列的数据集。大多数字符列都是简单的“是”或“否”问题,但有些不是。对于数字列,我觉得我有一个有效的解决方案。对于字符列,我尝试最小化它,但没有成功我想做并尝试的是一个循环,它指出当j=var4的列数时,使用大/小/IU替换。这个想法是,这将减少代码的“变量依赖性”,因为我可以在%let语句中更改var4的变量,并且代码的长度将更短

由于dim语句给出了数字或字符列的总数,我猜有一些语句给出了特定变量的列位置,我将用于secound循环。但是,我没有发现这样的说法

我的代码到目前为止

%let v1 = var1;
%let v2 = var2;
%let v3 = var3;
%let v4 = var4;

data have;
infile datalines delimiter = '|'; 
input surveyYear id var1 var2$ var3 var4$20. ;
datalines;
2016 |  1 |     10 |   Yes |     5 |   BIG
2016 |  2 |      6 |   YES |     8 |   Big
2016 |  3 |      8 |   YEs | 99999 |   big
2016 |  4 |      . |   yes |     5 | 99999
2017 |  5 |      6 |    No |     7 | SMALL
2017 |  6 |      5 |    Ye |     . | small
2017 |  7 |  99999 |    no |     3 | 99999
2018 |  8 |      3 | 99999 |     1 | SMall
2018 |  9 |      2 |    iu |     2 |    IU
2018 | 10 |     15 |    IU |     . |    Iu
;
run; 

data want;
set have;

    array var_num[*] _numeric_;
    do i=3 to dim(var_num);
        if var_num[i] = 99999 then var_num[i] = .;
    end;

    array var_cha[*] _character_;
    do j=1 to dim(var_cha);
        var_cha(j) = upcase(var_cha(j));
        if var_cha[j]  = 'YES'     then var_cha[j] = 'Yes';
        if var_cha[j]  = 'NO'      then var_cha[j] = 'No';
        if var_cha[j]  = 'IU'      then var_cha[j] = 'IU';
        if var_cha[j]  = '99999'   then var_cha[j] = 'IU';
        if var_cha[j]  = ''        then var_cha[j] = 'IU';
    end;
/* Integrate the code below into the loop*/
    if &v4 = 'BIG'     then &v4 = 'Big city';
    if &v4 = 'SMALL'   then &v4 = 'Small city';
    if &v4 = 'IU'      then &v4 = 'Unknow city size';
    if &v4 = '99999'   then &v4 = 'Unknow city size';

drop i j;
run;
我想如何编程的概念性想法

data want;
set have;
array var_cha[*] _character_;
    do j=1 to dim(var_cha);
        var_cha(j) = upcase(var_cha(j));
/*      All of the if statements for the yes, no and IU */

        if var_cha[j] = ColumnNumerOfVar4 then do;
        /* where ColumnNumerOfVar4 is equal to the column number of var4*/
            if var_cha[j] =  'BIG'      then var_cha[j] = 'Big city';
            if var_cha[j] =  'SMALL'    then var_cha[j] = 'Small city';
            if var_cha[j] =  'IU'       then var_cha[j] = 'Unknow city size';
            if var_cha[j] =  '99999'    then var_cha[j] = 'Unknow city size';
        end;
    end;
run;

如果需要获取数组中变量的名称,可以使用vName函数:

    if (vName(var_cha[j]) = 'var4') then do;
    /* where ColumnNumberOfVar4 is equal to the column number of var4*/
        if var_cha[j] =  'BIG'      then var_cha[j] = 'Big city';
        if var_cha[j] =  'SMALL'    then var_cha[j] = 'Small city';
        if var_cha[j] =  'IU'       then var_cha[j] = 'Unknow city size';
        if var_cha[j] =  '99999'    then var_cha[j] = 'Unknow city size';
    end;
据我所知,这将解决你的问题。但是,如果还想获取特定变量的列号,可以通过查看sasHelp.vColumns并将该数字放入宏变量中来实现。或者在数据步骤开始时执行类似操作:

retain columnNumberOfVar4;
if (_n_ eq 1) then do;
    id = open("work.have","i");
    num = attrn(id,"nvars");
    columnNumberOfVar4 = varNum(id, 'var4');
    rc = close(id);
end;

但我相信这并不是您在本例中需要做的。

也许我并不完全理解您想要什么,但看起来您只是想用do循环应用的变量名列表创建一个宏变量,并使用它来定义数组

%let yesnovars=var4 ;
array yesno &yesnovars;
然后,您可以执行如下循环:

 do j=1 to dim(yesno);
    yesno(j) = upcase(yesno(j));
    if yesno[j]  = 'YES'     then yesno[j] = 'Yes';
    if yesno[j]  = 'NO'      then yesno[j] = 'No';
    if yesno[j]  = 'IU'      then yesno[j] = 'IU';
    if yesno[j]  = '99999'   then yesno[j] = 'IU';
    if yesno[j]  = ''        then yesno[j] = 'IU';
 end;
但看起来您只是想对值应用格式。
因此,如果定义了$YESNO格式和$CITYSIZE格式,则可以执行类似操作,将所有字符变量从原始值转换为格式化值。只需记住将它们定义为足够长的时间来保存格式化的值,而不仅仅是原始值

format var2 $yesno. var4 $citysize.;
array _c _character_;
do j=1 to dim(_c);
  _c(j)=vvalue(_c(i));
end;

或者更好地定义信息并在读取原始数据时使用它们。

我认为您希望VNAME()函数测试变量是否是您认为的那样?我不想测试变量是否是我认为的那样。我想知道他们的数字位置。在我的例子中,dim(var_cha)会给我一个最大j值3。J=1是var2所有字符列的数字位置,J=2是var4所有字符列的数字位置。我想要的是将var4(在本例2中)的数字位置放在X中,然后声明如果var_cha[j]=X,则执行以下if语句。但我不知道如何找到X。老实说,不清楚你想做什么。J是索引,这是变量在数组中的位置。答案的多样性表明,其他人也不清楚你在问什么。我想我解释得更好,但正如答案的多样性所表明的,你是对的!我试图循环通过一定数量的数字和字符变量,但跳过其中的一个特定变量。假设我有10个字符变量。其中8个变量有简单的“是”或“否”答案,但其中2个字符变量有相同的输入(例如“大”和“小”),但应该有不同的输出(一个变量中“大”是“大城市”,另一个变量中是“大蛋糕”)。我试着在循环中确定一种方法,用它们的特定文本替换这2个变量。换句话说,将第一个代码(到目前为止我的代码标题)中的最后一部分代码集成到循环中。我发布的代码将完成我需要它做的事情,但我认为如果一切都在循环中,它会更干净。在matlab中,我可以通过[row-col]来确定它。我希望这能让事情变得更清楚?我已经有了替换是、否和IU部分的代码。我想要的是将大/小/IU集成到循环中,但在循环中声明,如果j等于某个变量(例如Var4),则执行其他stud。例如,在我的真实数据集中,有几个变量具有相同的输入(大、小或IU),但它们的含义不同。因此,我想知道是否有一种简单的方法来确定这些变量的列位置。例如,MATLAB[row col]我要说的是不需要在同一个循环中。为每个要重新编码的变量类创建单独的数组和循环。这会更清楚。它感觉这可能接近我想要的,但是你可以通过它的变量名而不是它的数字位置来确定位置。但是,当我尝试运行代码时,它会说“需要一个算术运算符”。对于if station,哪部分运行时有错误?我想我都查过了。要通过名称获取变量位置,可以使用varNum(id,“var4”)。它将为您提供名为“var4”的变量在数据集中的位置。如果(vName(var_cha[j])='var4',则执行;获取错误。表示'var4'需要算术运算符。看起来这是一个旧版本。很抱歉,一开始我犯了一个错误,错过了一个右大括号。应该是(vName(var_cha[j])='var4')这取决于任务,但在大多数情况下,我引用的是变量名,而不是它的位置。我认为SAS/Base中的数组功能非常差,因此您必须使用SAS数据集(表)并按名称引用所有变量。