4

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...

11
  • Is this the exact code you're trying to replicate or a simplified example? Commented Aug 5, 2015 at 19:17
  • @Reeza the computation piece is about the same, but the last step is much more complex. Commented Aug 5, 2015 at 19:19
  • @gt6989b You should probably include a more complete example of your actual problem; what you describe above could be trivially done without any need for macro variable arrays. In particular, is the creation of the macro variable actually just exp(i+1)? In that case why not just incorporate that in the final step (total = total + exp(i+1);)? Commented Aug 5, 2015 at 19:38
  • As far as macro variable arrays, look at my answer here; is that something like what you're trying to do? It's probably not the best way to do what you're doing, but it could work. Commented Aug 5, 2015 at 19:40
  • @Joe I updated the question code Commented Aug 5, 2015 at 19:45

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

16 Comments

My computational data step uses a data set of 100K+ records, running each of the 10K computations in my code for each of those records. How would I recycle the data in the same step without having pre-calc repeated for each record??
He's describing a macro array, presumably, which while not a technical feature of the language, is something i'd call acceptable terminology at this point.
No, the first loop will only execute once, just after reading in the first row from veryLargeDataset - that's what the if _n_ = 1 is for.
If you don't need the values saved for future use, I think this is the way to go. This is nearly the same as my second example, except skipping the output of those values - so if you do want them, do it like in mine.
Don't forget to include a call streaminit(some number) of course inside your if _n_=1 block before the rand, also, so you can reproduce your data :)
|
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.