2015-06-15 22 views
7

Sto definendo una variabile macro all'interno di una macro. Quindi, lo sto alimentando in una seconda macro. All'interno del contatore macro2 cambia il valore a 200. Tuttavia, quando controllo ciò che è all'interno della variabile macro che inserisco dopo la macro 2, continua a indicare 0. Vorrei che memorizzasse il valore 200? È possibile?Modifica del valore della variabile macro all'interno della macro SAS

%macro macro1(); 
    %let variable1= 0; 
    macro2(counter=&variable1) 

    %put &variable1; 
%mend macro1; 

%macro1; 

risposta

9

Hai un paio di problemi qui. Prima di tutto, ti manca lo % prima della tua chiamata a macro2, ma ho il sospetto che sia solo un refuso. Il problema principale è che si sta tentando di fare ciò che viene definito in altre lingue come call-by-reference. È possibile farlo nella macro SAS passando il il nome della variabile piuttosto che il valore della variabile e quindi utilizzare una sintassi funky & per impostare la variabile di tale nome su un nuovo valore.

Ecco alcuni esempi di codice che fa questo:

%macro macro2(counter_name); 
    /* The following code translates to: 
    "Let the variable whose name is stored in counter_name equal 
    the value of the variable whose name is stored in counter_name 
    plus 1." */ 

    %LET &counter_name = %EVAL (&&&counter_name + 1); 

%mend; 

%macro macro1(); 
    %let variable1= 0; 

    /* Try it once - see a 1 */ 
    /* Notice how we're passing 'variable1', not '&variable1' */ 
    %macro2(counter_name = variable1) 
    %put &variable1; 

    /* Try it twice - see a 2 */ 
    /* Notice how we're passing 'variable1', not '&variable1' */ 
    %macro2(counter_name = variable1) 
    %put &variable1; 
%mend macro1; 

%macro1; 

Mi hanno fatto un altro post su StackOverflow che ha una spiegazione della sintassi &&&; puoi have a look at it here. Si noti che la chiamata %EVAL non ha nulla a che fare con la chiamata per riferimento, è solo lì per fare l'aggiunta.

+1

Grazie, punto preso ... Ridurrò un po 'il linguaggio. –

+1

Grazie per l'aggiornamento! – Joe

+1

Grazie, ha senso, penso. Ci proverò domani. Tuttavia, mi chiedo se questo significa che non posso avere macro2 abbastanza generale da prendere valori o variabili macro. Come è scritto sopra, ora è limitato solo a prendere variabili macro? – DanRoDuq

2

Sparc_Spread spiega come "chiamare per riferimento" nel linguaggio macro SAS, che può risolvere il problema.

In questo caso particolare, tuttavia, non è cruciale utilizzare la chiamata per riferimento, e direi che non è un linguaggio idiomatico con SAS per usarlo (anche se certamente non ha nulla di sbagliato in questo - sembra solo un po 'strano, ed è un po 'più difficile dal momento che non è davvero un concetto nativo, anche se certamente supportato intenzionalmente per essere usato in questo modo se lo si desidera). Ci sono due modi per aggirare ciò che entrambi sono molto facili da usare.

Prima di tutto, diciamo di conoscere il nome della variabile che si desidera incrementare e il valore iniziale è l'unica cosa interessante. Grazie al modo in cui il linguaggio macro SAS gestisce l'ambito, con qualcosa che non è esattamente scopico lessicale e non esattamente funzionale, utilizzerà automaticamente la variabile che già esiste nello scope più locale, quando già esiste (con alcune avvertenze minori, come le macro che usano DOSUBL).

Quindi, questo funziona come previsto:

%macro macro2(counter=); 
    %do variable1 =&counter. %to 200; 
    %if %sysfunc(mod(&variable1.,50))=0 %then %put &=variable1; 
    %end; 

%mend macro2; 

%macro macro1(); 
    %let variable1= 0; 
    %macro2(counter=&variable1.); 

    %put &=variable1; 
%mend macro1; 

%macro1; 

(Naturalmente, cioè se si aspetta & variabile1 abbia il valore di 201 - perché %do loop, come do loop, sempre ottenere aumentato di uno rispetto la loro . valore finale presumo vostra procedura reale funziona in modo diverso)

questo perché il &variable1. cui %macro2 è automaticamente quello presente nel campo di applicazione più locali -. che in questo caso è la portata %macro1.


In alternativa, se si sta utilizzando questo %macro2 allo scopo di incrementare un contatore, vorrei utilizzare un metodo function-style macro.

Una macro di stile funzione per definizione è uno che restituisce solo un singolo valore e per returns intendo un singolo valore alla fine del codice della macro presentato in testo semplice (poiché una macro è, dopo tutto , inteso solo per creare testo che verrà poi analizzato dal normale parser di linguaggio SAS).

Questo può quindi essere utilizzato sul lato destro di un segno di uguale in un estratto conto. La chiave è che utilizza solo elementi di linguaggio macro - %do loop e tale - e nessun passo di dati, proc, ecc., Linguaggio che impedirebbe di trovarsi sul lato destro di un segno di uguale in un'istruzione di assegnazione (cioè, x=%macrostuff(); non può essere x=proc sql(select...)).

Quindi il seguente raggiunge l'obiettivo: incrementare un contatore di qualche importo, restituire il valore (201, in questo caso, proprio come prima), e quindi che può essere assegnato a una variabile macro.

%macro macro2(counter=); 
    %do internal_counter =&counter. %to 200; 
    %if %sysfunc(mod(&internal_counter.,50))=0 %then %put &=internal_counter.; 
    %end; 
    &internal_counter. 
%mend macro2; 

%macro macro1(); 
    %let variable1= %macro2(counter=0); 

    %put &=variable1; 
%mend macro1; 

%macro1; 

vorrei suggerire che questo è il modo più idiomatico per raggiungere questo obiettivo, e la più semplice: si passa il valore che si desidera come input, funzione opera su di esso, restituisce il valore, che poi assegna ad una variabile nella tua macro come vuoi tu.

+0

+1 risolve anche il problema. Non ho mai saputo della sintassi '& ='! Molto utile per il debug, ecc. È sempre stato in SAS? Ho letto il libro Purple Carpenter più volte e non credo di averlo mai visto. –

+1

'& =' è nuovo come da 9.3 Penso (o forse 9.2) - è un bel ritocco secondario! – Joe

+0

Lo è sicuramente. Grazie per averlo pubblicato! –

Problemi correlati