数字と文字をまとめて,見せかけ上,型混合ARRAY配列っぽく処理してしまう

 いいのか悪いのかわからないのですが,SASのARRAYは文字型変数と数値型変数をまぜて作れないので,少し不便なことがあります.
まず 処理したい変数をくくって,そこから文字変数はこう処理,数値変数はこうってしたいことってあると思うんですよね.ってことで,それっぽいマクロを作りました

%macro x_array(list=,

                       ch_code=,

                       num_code=,

                       array_no=

                       );

 %let list=%sysfunc(upcase(%sysfunc(compbl(&list))));

 %let qlist  = %sysfunc( tranwrd( %str("&list") , %str( ) , %str(",") ) );

 %let itemnum = %sysfunc( count( &list, %str ( ) ));

_banpei_num=.;

_banpei_char="";

array arch&array_no. _character_;

array arnum&array_no. _numeric_;

do over arch;

 if upcase(vname(arch&array_no.)) in (&qlist) then do;

  arch&array_no.=arch&array_no.;

    &ch_code;

 end;

end;

do over arnum&array_no.;

 if upcase(vname(arnum&array_no.)) in (&qlist) then do;

  arnum&array_no.=arnum&array_no.;

&num_code;

 end;

end;

drop _banpei_num _banpei_char;

%mend;


例えば以下のようなテストデータ
data test;
length C1 $20. N1 8. C2 $20. N2 8. C3 $20. N3 8. Z1-Z3 $20.;
C1="A";
N1=1;
C2="B";
N2=2;
C3="C";
N3=3;
Z1="1";
Z2="2";
Z3="3";
output;
run;










C1-C3に文字でABC
N1-3は数値で1-3入れて
Z1ーZ3には文字で1-3入れてます

ここで適当に

ここで,

① C1,C3,N1で 型混合配列1として定義し,配列内の文字型要素を---に数字型要素を1000倍

② C2,N2で 型混合配列2として定義し,配列内の文字型要素を3倍繰り返しに数字型要素を正負反転処理

③ Z1 Z2 Z3を型混合配列3として定義し,文字で入ってるけど,すべて数値に変えて,合計値をZSUMとして求める

とかって 処理をしたい時にさっきのマクロで

data out;

set test;

%x_array(list=C1 C3 N1

              ,ch_code=%str(arch='---')

              ,num_code=%str(arnum = arnum*1000 )

             );


%x_array(list=C2  N2

  ,array_no=1

              ,ch_code=%str(arch1=compress(repeat(arch1,2)))

              ,num_code=%str(arnum1 = arnum1*-1 )

             );


array NZ NZ1-NZ99;

%x_array(list=Z1 Z2 Z3

  ,array_no=2

              ,ch_code=%str(

NZ=input(arch2,best.);

)

             );

ZSUM=sum(of NZ:);

put ZSUM=;

drop NZ:;

run;

こんな風に書けば







まあ,できちゃうよと.


別途,C: みたいにコロンモディファイアでリスト指定したいとか
N1-N3とかで連番指定 C1--Z1みたいな位置していで型混合配列にしたい場合

事前に変数リストを作るマクロも作りました


%macro varlist_modi(ds=, modi=,listno=1);
ods output Position=Position;
proc contents data=&ds varnum ;
run;
ods output close;
proc transpose data=Position out=_Position;
 var num;
 id Variable;
run;
options dkricond=nowarn;
data _Position;
set _Position(drop=_label_ _name_);
run;
data _null;
set _Position(drop=_label_ _name_);
length _namelist $1000.;
array ar &modi.;
do over ar;
 _namelist=catx(' ',_namelist,upcase(vname(ar)));
end;
call symputx("namelist&listno.",_namelist,'G');
run;
%put NOTE: [namelist&listno.] created: &&namelist&listno.;
options dkricond=error;
%mend;


%varlist_modi(listno=1,ds=test,modi=C:);
とすれば
&namelist1 というマクロ変数の中に C1 C2 C3という データに基づいて生成された
リストができるので,それを先のマクロで指定してくださいってことですね

ただ,良し悪しかなと思うのは
SASは2つしか型がなくて,それはSASの根幹の部分なので,それを見せかけ上マスクしてしまうのは,作業的には便利なんですが,プログラム的にはどうなのかなと思わなくもないですね.
明示的に数値は数値の処理,文字は文字の処理って書いたほうが綺麗な気もします