Reputation:
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
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
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
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