もうハッシュオブジェクトの話もウンザリかもしれませんので、とりあえず今回で一段落です。
本当はここからさらに、新世界である「ハッシュ反復子オブジェクト」というものがあります
簡単にいうと、ハッシュオブジェクトの進化版で、もはやkey-data構造から解放され、まるでデータステップを並行して走らせているかのような柔軟な処理ができます。
でも僕自身の理解がまだ進んでないので、記事にするのは先になると思います。
ただ今回は、今回はそんな「ハッシュ反復子オブジェクト」の1歩手前の話です。
ハッシュオブジェクトはkeyとdataで構成され、keyによって原則的に一意でなっていなければならないと説明したと思います。
原則ということは例外も作れるということで、今回は重複を許したkeyを持つハッシュオブジェクトの話です。
さて
data Q1;
X=1;A=2;output;
X=1;A=3;output;
X=2;A=3;output;
X=3;A=1;output;
run;
data Q2;
X=1;Y=2;Z='A';output;
X=1;Y=4;Z='B';output;
X=1;Y=5;Z='C';output;
X=2;Y=1;Z='D';output;
X=2;Y=2;Z='E';output;
X=2;Y=3;Z='F';output;
X=3;Y=6;Z='G';output;
X=3;Y=7;Z='H';output;
run;
上記2つのデータセットをXの値で両側外部結合して、Y>Aとなるオブザベーションのみを残すという
処理を考えます。
すなわちSQLで書くなら
proc sql noprint;
create table A0 as
select coalesce(Q1.X,Q2.X) as X
,A
,Y
,Z
from Q1 full outer join Q2 on Q1.X=Q2.X
where Y>A
order by X,A,Z
;
quit;
となって、以下が求めるべき結果です。
Xの値によって結合するわけですが、両方のデータセットともXで一意にならないという、遭遇すると
うざい状況ですね。
またcross joinやfull outer joinはご存知の通り、オブザベーション数があまり膨大になると、処理時間が、止まってんじゃないのこれ?状態になります。
さて、これをハッシュでやるのはどうしましょうか?
本来、小さいほうのQ1をハッシュに入れた方がいいのですが、今回は説明のためQ2を入れます。
data A1;
if _N_=0 then set Q1 Q2;
if _N_=1 then do;
declare hash hq1(dataset:'Q2', multidata: 'y');
hq1.definekey('X');
hq1.definedata('Y', 'Z');
hq1.definedone();
end;
set Q1;
rc=hq1.find();
if rc=0 and Y>A then output;
do while(rc=0);
rc=hq1.find_next();
if rc=0 and Y>A then output;
end;
drop rc;
run;
これでさっきのSQLとまったく同じ結果になります。
味噌なのはmultidata: 'y'です。これによって、ハッシュの中で同じXの値が共存できます。
そして大事なのがfindメソッドでXに対応するY Zをとった後に、もしかしたら、まだハッシュに同じXの値に対応するデータがあるかもしれないから次を探索するという処理を書いているということです。
do while(rc=0);rc=メソッド;end;の形は、定跡形ともいえる基本的なテクニックなので覚えてください。つまりメソッドが成功している限り、続けるという意味です。
find_nextメソッドは直前のfindメソッドまたはfind_nextメソッドによって参照されたkeyの次のkeyをfindするメソッドです。
超要注意なのは、上記プログラムのfind_next()をfind()にすると、一つでも一致するkeyがあれば同じキーを何度も参照し、当然、rcは常に0となってしまい、無限ループの世界へようこそになってしまいます。まあ、実験でやってみてもいいですが、大事なものは保存してからにしてください。バツ印アイコン押せば、ステップの終了できるはずなんですが、僕のSASは何故か反応せずにSASごと強制的に閉じるはめになりましたので。
0 件のコメント:
コメントを投稿