user1980542
user1980542

Reputation:

Reading observations from SAS dataset into arrays

This question relates to SAS on Mainframe, although I believe it doesn't make a difference in this situation.

I have the following SAS dataset:

Obs     DATO    T_ALLOC    T_FRESP

 1     19328      647        1804 
 2     19359      654        1797 
 3     19390      662        1789 
 4     19418      676        1774 
 5     19449      636        1815 
 6     19479      698        1753 

My goal is to place all 6 observations of the 3 variables (I hope I use the correct terminology here), into seperate arrays.

I have made a great effort of reading up on working with arrays, but for some reason the solution for this particular problem have eluded me.

If anyone would be as kind as to provide a helping hand it would be much appreciated. Even a link to documentation containing the answer im looking for, would be very helpful.

If i am unclear in my explanation, please tell me so, and i will provide any additional information necessary.

Thanks in advance.

EDIT->

My final CSV should look similar to this:

Datoer,01/2013,02/2013,03/2013,04/2013,05/2013,06/2013,07/2013,08/2013,09/2013,10/2013
Freespace,800,1000,1243,1387,1457,1562,1620,1700,1800,1900
Allokeret,1000,1200,1456,1689,1784,1865,1930,2000,2100,2200

Upvotes: 4

Views: 17033

Answers (3)

natsja
natsja

Reputation: 56

You can get the result you want with the help of proc transpose, if I understood your needs correctly.

proc transpose data = datain out = dataout;
    var DATO T_ALLOC T_FRESP;
run;

proc export data=dataout
    outfile='xxxxx\tmp.csv'
    dbms=csv
    replace;
run;

Just another idea with SQL.

proc sql noprint;
    select DATO into :dato separated by ',' from datain;
    select T_ALLOC into :talloc separated by ',' from datain;
    select T_FRESP into :tfresp separated by ',' from datain;
quit;

data _NULL_;
    file 'xxxxx\tmp.csv';
    put "var1,&dato";
    put "var2,&talloc";
    put "var3,&tfresp";
run;

And another one with arrays.

data _NULL_;
    set datain nobs = nobs;
    array data DATO T_ALLOC T_FRESP;
    format t1-t3 $50.;
    retain t1-t3;
    array t[3] $;
    do i = 1 to dim(t);
        if _N_ = 1 then t[i] = put(data[i], 8.);
            else t[i] = compress(t[i] || ',' || put(data[i], 8.));
    end;
    if _N_ = nobs;
    file 'xxxxx\tmp.csv';
    put "var1," t1;
    put "var2," t2;
    put "var3," t3;
run;

Upvotes: 4

BellevueBob
BellevueBob

Reputation: 9618

Natsja's answer is a good one (as long as all your values are numeric). But since you asked about arrays, here is a more long-winded answer using arrays and traditional data step processing:

data have;
   input DATO T_ALLOC T_FRESP;
   datalines;
19328      647        1804 
19359      654        1797 
19390      662        1789 
19418      676        1774 
19449      636        1815 
19479      698        1753 
run;

/* Find number of records in data set */
/* The "separated by" clause is a trick to trim leading blanks */
proc sql noprint;
   select count(*) into :num_recs separated by ','
   from have;
quit;

data _null_;
   /* Define variables wanted */
   /* These could be defined as _TEMPORARY_ arrays but I left them as */
   /* creating actual variables for illustration.                     */
   array a(&num_recs) DATO1-DATO&num_recs;
   array b(&num_recs) T_ALLOC1-T_ALLOC&num_recs;
   array c(&num_recs) T_FRESP1-T_FRESP&num_recs;

   /* Load the arrays */
   do while(not eof);
      set have end=eof;
      _i_ + 1;
      a(_i_) = DATO;
      b(_i_) = T_ALLOC;
      c(_i_) = T_FRESP;
      end;

   /* Create the CSV file with three records */
   file 'c:\temp\wanted.csv' dlm=',';

   length header $10;
   header = 'Datoer';
   put header @;
   do _i_ = 1 to dim(a);
      put a(_i_) :mmyys. @;
      end;
   put;
   header = 'Freespace';   
   put header @;
   do _i_ = 1 to dim(b);
      put b(_i_) @;
      end;
   put;
   header = 'Allokeret,';   
   put header @;
   do _i_ = 1 to dim(c);
      put c(_i_) @;
      end;
   put;

   /* Explicitly stop the data step in this example */
   stop;
run;

I've "enhanced" the answer to allow for a variable number of rows in your starting data set.

Also, you mentioned running on a mainframe: the only change needed should be a operating system specific FILE statement.

UPDATED: Revised answer based on Joe's helpful comment.

Upvotes: 4

Joe
Joe

Reputation: 63424

I was just about to post this when Bob posted his; I'll go ahead and post it anyway as it shows a few different concepts from his. If you don't want the intermediate dataset, and have a fairly big dataset, then your best bet is probably a combination of the two.

data have;
input DATO    T_ALLOC    T_FRESP;
datalines;
19328      647        1804 
19359      654        1797 
19390      662        1789 
19418      676        1774 
19449      636        1815 
19479      698        1753 
;;;;
run;

*Get the array parameter;
proc sql noprint;
select count(1) into :reccount from have ;
quit;

data want;
length varname $8;
*Define the intermediate arrays as _temporary_ so they are stored in memory only;
array datos[&reccount] _temporary_;
array tallocs[&reccount] _temporary_;
array tfresps[&reccount] _temporary_;
*The final array that will be written out is stored in physical disk space;
*If you write this out to a file directly this array can be skipped;
array final_vars[&reccount];

do _t = 1 to &reccount;
 set have;
 datos[_t]=dato;
 tallocs[_t]=t_alloc;
 tfresps[_t]=t_fresp;
end;

*If I were doing this I would write a macro to do this part, as it is the same thing three times;
varname="DATO";
do _t = 1 to &reccount;
 final_vars[_t]=datos[_t];
end;
output;

varname="T_ALLOC";
do _t = 1 to &reccount;
 final_vars[_t]=tallocs[_t];
end;
output;

varname="T_FRESP";
do _t = 1 to &reccount;
 final_vars[_t]=tfresps[_t];
end;
output;

keep final_vars: varname;
run;

Upvotes: 0

Related Questions