Reputation: 4203
I am a SAS beginner. I have an array-like piece of data in my code, which needs to be passed to a different data step much lower in the code to do computations with it. My code does something like this (computation simplified for this example):
data _null_;
call symput('numRuns', 10000);
run;
/* this is the pre-computation step, building CompressArray for later use */
data _null_;
do i = 1 to &numRuns;
value = exp(rand('NORMAL', 0.1, 0.5)));
call symput(compress('CompressArray'||i), value);
end;
run;
data reportData;
set veryLargeDataSet; /* 100K+ observations on 30+ vars */
array outputValues[10000];
do i = 1 to &numRuns;
precomputedValue = symget(compress('CompressArray'||i));
outputValues[i] = /* calculation using precomputedValue */
end;
run;
I am trying to redo this using arrays, is that possible? E.g. to store it in some global array and access it later...
Upvotes: 4
Views: 1192
Reputation: 9569
Arrays in SAS only exist for the duration of the data step in which they are created. You would need to save the contents of your array in a dataset or, as you have done, in a series of macro variables.
Alternatively, you might be able to rewrite some of your code to do all of the work that uses the array within one data step. DOW-loops are quite good in this regard.
Based on the updates to your question, it sounds as though you could use a temporary array to do what you want:
data reportData;
set veryLargeDataSet; /* 100K+ observations on 30+ vars */
array outputValues[&numruns];
array precomputed[&numruns] _temporary_;
if _n_ = 1 then do i = 1 to &numruns;
if i = 1 then call streaminit(1);
precomputed[i] = exp(rand('NORMAL', &meanNorm, &stDevNorm));
end;
do i = 1 to &numRuns;
outputValues[i] = /* calculation using precomputed[i] */
end;
run;
Defining an array as _temporary_
causes the values of the array elements to be retained across iterations of the data step, so you only have to populate it once and then you can use it for the rest of the data step.
Upvotes: 4
Reputation: 63424
There are a lot of ways to do this, but the hash table lookup is one of the most straightforward.
%let meannorm=5;
%let stDevNorm=1;
%let numRuns=10000;
/* this is the pre-computation step, building CompressArray for later use */
data my_values;
call streaminit(7);
do i = 1 to &numRuns;
Value= rand('Normal',&meannorm., &stDevNorm.);
output;
end;
run;
data reportData;
if _n_=1 then do;
declare hash h(dataset:'my_values');
h.defineKey('i'); *the "key" you are looking up from;
h.defineData('value'); *what you want back;
h.defineDone();
call missing(of i value);
end;
set sashelp.class; /* 100K+ observations on 30+ vars */
array outputValues[10000];
do i = 1 to &numRuns;
rc=h.find();
outputValues[i] = value;
end;
run;
Basically, you need to 'load' the table in some fashion and do [something] with it. Here's one easy way.
In your particular example there's another pretty simple way: bring it in an as array.
In this case we don't put 10k rows out, but 10k variables - then declare it as an array (again) in the new data step. (Arrays are, as noted by user667489, transient; they're not stored on the dataset in any way, except as the underlying variables, so they have to be re-declared each data step.)
%let meannorm=5;
%let stDevNorm=1;
%let numRuns=10000;
/* this is the pre-computation step, building CompressArray for later use */
data my_values;
call streaminit(7);
array values[&numruns.];
do i = 1 to &numRuns;
Values[i]= rand('Normal',&meannorm., &stDevNorm.);
end;
run;
data reportData;
if _n_=1 then set my_values(drop=i);
set sashelp.class; /* 100K+ observations on 30+ vars */
array outputValues[&numruns.];
array values[&numruns.]; *this comes from my_values;
do i = 1 to &numRuns;
outputValues[i] = values[i];
end;
drop values:;
run;
Here note that I have the set in if _n_=1
still - otherwise it would terminate the data step after the first iteration.
You could also use a format, as Reeza notes, or several other options - but I think these are the simplest.
Upvotes: 2