2014-09-10 32 views
0

我試圖編寫健壯的代碼來爲宏變量賦值。我希望宏變量的名稱取決於來自變量「子組」的值。因此,小組可以等於1,2或45等,因此具有宏變量名稱trta_1,trta_2,trt_45等。如何在宏變量名稱中使用%SCAN?

我遇到困難的地方是調用宏變量名稱。因此,不要打電話給& trta_1我想調用& trta_%SCAN(&子組,& k),它在第一次迭代時解析爲trta_1。我在宏變量名稱中使用了%SCAN函數,該函數拋出警告'WARNING:明顯的符號引用TRTA_未解決。'。但是,宏變量已使用賦值分配。

如何解決警告?有沒有我可以用%SCAN函數運行的函數來實現這個功能?

data data1 ; 
    input subgroup trta trtb ; 
    datalines ; 
    1 30 58 
    2 120 450 
    3 670 3 
run; 

%LET subgroups = 1 2 3 ; 
%PUT &subgroups; 

%MACRO test; 
    %DO k=1 %TO 3; 

    DATA test_&k; 
     SET data1; 
     WHERE subgroup = %SCAN(&subgroups, &k); 
     CALL SYMPUTX("TRTA_%SCAN(&subgroups, &k)", trta, 'G'); 
     CALL SYMPUTX("TRTB_%SCAN(&subgroups, &k)", trtb, 'G'); 
    RUN; 

    %PUT "&TRTA_%SCAN(&subgroups, &k)" "&TRTB_%SCAN(&subgroups, &k)"; 
    %END; 

%MEND test; 
%test; 
+0

你已經在你的宏中使用過&子組,但是'&subtest'在外? – DTS 2014-09-10 12:53:26

+0

@dennis suter嗯,是的,我正在測試它,忘了改回來,謝謝!現在更新了。 – Dawnoak 2014-09-10 13:05:00

回答

1

使用您提供的結構將實現您正在尋找的結果。

data data1; 
    input subgroup trta trtb; 
    datalines; 
1 30 58 
2 120 450 
3 670 3 
; 
run; 

%LET SUBGROUPS = 1 2 3; 
%PUT &SUBGROUPS; 

%MACRO TEST; 
    %DO K=1 %TO 3; 

    %LET X = %SCAN(&SUBGROUPS, &K) ; 

    data test_&k; 
     set data1; 
     where subgroup = &X ; 
     call symputx(cats("TRTA_",&X), trta, 'g'); 
     call symputx(cats("TRTB_",&X), trtb, 'g'); 
    run; 

    %PUT "&&TRTA_&X" "&&TRTB_&X"; 
    %END; 
%MEND TEST; 
%TEST; 

但是,我不確定這種方法是否特別穩健。如果您的子組列表發生變化,您需要手動更改'K'循環,您可以通過動態計算子組列表中的'元素'來確定循環的上限。

如果您想調用稍後在代碼中創建的宏變量,您可以使用類似的方法。

data data2; 
    input subgroup value; 
    datalines; 
1 20 
2 25 
3 15 
45 30 
    ; 
run ; 


%MACRO TEST2; 
    %DO K=1 %TO 3; 

    %LET X = %SCAN(&SUBGROUPS, &K) ; 

    data data2 ; 
     set data2 ; 
     if subgroup = &X then percent = value/&&TRTB_&X ; 
     format percent percent9.2 ;  
    run ; 
    %END; 
%MEND TEST2; 

%TEST2 ; 

實際上,您正在重寫循環的每次迭代中的data2。

+0

這將工作。然而,我應該說的是,我想使用該宏以外的宏變量,所以我希望能夠在其他地方的代碼中調用&trta_1或&trta_2或&trtb_3或&trtb_45等。在後面的代碼中,例如,如果subgroup = 45,那麼percent = value /&trtb_45,只有我使用%scan(&subgroups,&k),所以我沒有明確說明trtb_45,因爲它可能在另一個re - 運行trtb_309。 – Dawnoak 2014-09-10 13:24:48

+1

編輯我的答案。只是想強調幾乎肯定有更好的方法來處理你的問題,但是如果不知道你在做什麼,就很難進一步提出建議。 – AJ7 2014-09-10 14:04:48

+0

是的,我認爲你就在那裏。我可以做到這一點,如果我在我的代碼中計算百分比時使用%let語句創建一個宏變量。它在我的宏變量名稱中使用%SCAN函數。也許稍後我可以弄清楚如何使用%掃描功能來做到這一點,但現在我很滿意你的建議 - 謝謝! – Dawnoak 2014-09-10 14:22:06

0

這應該涵蓋您的要求。您可以加載和卸載不帶宏的宏變量數組。我已經包含了一個替代方法,用宏來卸載一個宏變量數組進行比較。

將值加載到宏變量中,包括宏變量名稱內的子組編號例如TRTA_45。

data data1; 
    input subgroup trta trtb; 

    call symput ('TRTA_'||compress (subgroup), trta); 
    call symput ('TRTB_'||compress (subgroup), trtb); 

    datalines; 
    1 30 58 
    2 120 450 
    3 670 3 
    45 999 111 
    ; 
run; 

無需宏載入或引用宏變量。

%put TRTA_45: &TRTA_45.; 

%let Subgroup_num = 45; 

%put TRTB__&subgroup_num.: &&TRTB_&subgroup_num.; 

如果您需要遍歷宏變量,則可以使用Proc SQL生成子組列表。

proc sql noprint; 
select subgroup 
, count (*) 
into :subgroups separated by ' ' 
, :No_Subgroups 
from data1 
; 
quit; 

%put Subgroups: &subgroups.; 

%put No_Subgroups: &No_Subgroups.; 

使用宏循環遍歷宏變量數組並填充表。

%macro subgroups; 

data subgroup_data_macro; 

%do i = 1 %to &no_subgroups.; 
    %PUT TRTA_%SCAN(&subgroups, &i): %cmpres(&TRTA_%SCAN(&subgroups, &i)); 
    %PUT TRTB_%SCAN(&subgroups, &i): %cmpres(&TRTB_%SCAN(&subgroups, &i)); 

    subgroup = %SCAN(&subgroups, &i); 

    TRTA = %cmpres(&TRTA_%SCAN(&subgroups, &i)); 
    TRTB = %cmpres(&TRTB_%SCAN(&subgroups, &i));  

    output; 
%end; 
run; 
%mend subgroups; 

%subgroups; 

或者使用數據步驟(在宏外部)循環遍歷宏變量數組並填充表。

data subgroup_data_sans_macro; 

do i = 1 to &no_subgroups.; 
    subgroup = SCAN("&subgroups", i); 

    TRTA = input (symget (compress ('TRTA_'||subgroup)),20.); 
    TRTB = input (symget (compress ('TRTB_'||subgroup)),20.); 

    output; 
end; 
run;  

確保這兩種方法(內部和外部的宏)產生相同的結果。

proc compare 
base = subgroup_data_sans_macro 
compare = subgroup_data_macro 
; 
run;  
相關問題