2015年8月24日月曜日

一時配列(ARRAY _TEMPORARY_)はRETAIN機能をもってる


ARRAYステートメントにRETAIN機能を付与する小技」 の番外編。


ARRAYステートメントの変数名を指定する部分に「_TEMPORARY_」と指定すると、「一時データ要素」の配列を作ることが出来ます。

「一時データ要素」はデータステップ内でのみ存在し、終了したら消えます。


* テストデータ ;
data DT1;
input A;
cards;
1
.
.
2
.
;

 A  
 1 
 . 
 . 
 2 
 . 

* 一時配列の動きを確認してみる ;
data DT2;
   set DT1;
   array AR(1) _temporary_ ;
   if A^=. then AR(1) = A;
   A2=AR(1);
run;

 A  
 A2 
 1 
 1 
 . 
 1 
 . 
 
 2 
 2 
 . 
 2

一時データ要素はデータステップ終了とともに無くなってしまうので、適当にA2という変数を作って、そこに一時データ要素の値を入れて動きを確認しています。

A2を見ると、RETAINのように値が保持され続けてる事が確認できます。
この一時配列の性質を知っておくと結構役に立ちます。

8 件のコメント:

  1. これも使えそうで素晴らしいです!
    arrayで指定した要素数が複数あって、by変数の最初に、その複数の変数を初期化(欠損値あるいはゼロに)する方法は、スマートにどうすればよかったでしょうか?

    返信削除
    返信
    1. すみません。
      array AR{3} _Temporary_;のように複数の要素は使えないのかも・・・?
      先走りでした。

      削除
    2. いつもコメントありがとうございます!
      実験してみましたが、複数の要素も使えるようですよ。

      data DT1;
      input NO$ VAL1 VAL2;
      cards;
      001 10 100
      001 . .
      001 . 200
      002 . 300
      002 20 .
      002 . .
      ;
      run;

      data OUT1;
      set DT1;
      array VAL{2} VAL1 VAL2;
      array TEMP{2} _temporary_;

      do i=1 to dim(VAL);
      if VAL(i)^=. then TEMP(i)=VAL(i);
      end;

      * 2つの要素を変数に落とす ;
      TEST1 = TEMP(1);
      TEST2 = TEMP(2);
      run;


      またNO毎に変数を初期化したいような場合、私自身は以前書いた記事の方法を使っていっぺんに初期化してます。
      http://sas-boubi.blogspot.jp/2015/06/retain_13.html

      data OUT2;
      set DT1;
      by NO;
      array VAL{2} VAL1 VAL2;
      array TEMP{2} A1 A2 (2*.);

      do i=1 to dim(VAL);
      if VAL(i)^=. then TEMP(i)=VAL(i);
      end;

      output;
      if last.NO then call missing(of _ALL_);
      run;

      削除
    3. こちらのミスでした。
      それに、call missing( )も忘れていました。
      ありがとうございました!

      削除
    4. たびたび、すみません。

      下記プログラムは、性毎に60<身長の人が少なくとも一人以上いて、かつ120<体重の人が
      少なくとも一人以上いる場合に、それぞれ最後の行でXX=1とするつもりで書きました。

      しかし、うまくいきません(descendingを除去した場合と結果が異なることからも、うまく
      いかないことがわかります)。

      これは、call missing(of _Temporary_)が無効なのか、それともプログラムにミスがあるのでしょうか。


      proc sort data=Sashelp.Class out=Class;
      by descending Sex;
      run;

      data A1;
      set Class;
      by descending Sex;
      array AR{2} _Temporary_;
      if first.Sex then call missing(of _Temporary_);
      if 60<Height then Ar{1}=1;
      if 120<Weight then Ar{2}=1;
      if last.Sex & Ar{1} & Ar{2} then XX=1;
      run;

      削除
    5. どうもです!

      call missingの「_temporary_」が上手くいってないようです。
      if first.Sex then call missing(of _Temporary_);

      そこで以下のように「配列名(*)」で動くと思いますが、どうでしょうか?
      if first.Sex then call missing(of AR{*});

      削除
    6. このコメントは投稿者によって削除されました。

      削除
    7. ありがとうございます。これで完璧です!

      削除