Ansprechen einer Anzahl von Variablen über einen Schleifendurchlauf

Hallo,

offensichtlich ist mein Anliegen noch nicht diskutiert worden:
Ich habe (von Fall zu Fall verschieden viele) 2*anzm paarige Variablen, z. B. A1 A2 B1 B2 ..., deren Anzahl durch die Makrovariable 'anzm' übergeben wird.

Weiterhin enthält die Makrovariable 'marker', z. B. 'A B C ...' die "Stämme" der Namen.

Nun bereitet es keine Schwierigkeiten, die einzelnen Namens-Stämme über scan zu separieren, z. B. nacheinander in eine Variable 'string' oder ein Text-Array.
Wie aber kann man dann über eine Schleife die Werte der Variablen A1, A2, B1, B2 usw. auslesen?

Mein Problem ist, dass ich die Variablen nicht ansprechen kann.
Bei einem %LET-Statement z. B.

%LET M1 = string||1;
bzw.
%LET M2 = string||2;
wird nicht der Wert der Variablen 'string' mit 1 bzw 2 konkateniert, sondern in M1 und M2 steht einfach der blanke Text.

Für Ihre Hinweise bin ich dankbar.
Gruß
Meinhard Mende

Datastep oder Makro?

Was sind A1 A2 B1 B2 ... für Variablen? Makrovariablen oder Variablen in einem Datastep?

A1 A2 B1 B2 ... sind

A1 A2 B1 B2 ... sind Variablen eines vorhandenen Datasets.

Makro plus Array

Wenn es Dataset-Variablen sind, dann hilft vielleicht die folgende Lösung, die auf Basis der Informationen in den Makrovariablen zwei Arrays zusammenstellt, einen namens vars1 für alle Variablen, die mit 1 enden und einen zweiten für alle Variablen, die mit 2 enden. Anschließen kann man über die Arrays und über einen Index auf die Variablen zugreifen. Man kann natürlich auch alle Variablen in einen Array zusammenfassen, dann wird es aber schwieriger, darauf zuzugreifen.

/* beispieldaten erzeugen */
data test;
   a1=
1; a2= 2;
   b1=
3; b2= 4;   
   c1=
5; c2= 6;
   
output;
   a1=
7; a2= 8;
   b1=
9; b2=10;   
   c1=
11; c2=12;
   
output;
run;

/* makrovariablen definieren */
%let marker = a b c;
%let anzm = 3;
options mprint;

/* über Makroanweisungen auf die dataset-variablen zugreifen */
data _null_;
   
set test;

%macro schleife(einszwei);
   array vars&einszwei
/* ein Array fasst die Variablen zusammen */
%local i;
%let i=1;
%do %while ("%scan(&marker,&i)" NE "");
   
%scan(&marker,&i)&einszwei
   
%let i=%eval(&i+1);
%end;
   ;
%mend schleife;
%schleife(
1) /* array vars1 für alle Variablen, die mit 1 enden */
%schleife(2) /* array vars2 für alle Variablen, die mit 2 enden */
   
   
/* nur als Beispiel: auf die variablen über die beiden arrays zugreifen */
   
do index=1 to &anzm;
      
put vars1(index)= vars2(index)=; /* Variablenwerte in den Log ausgeben */
   
end;
run;

Arraydefinition über Schleife

Vielen Dank!
Der Kern meines Problems war, dass es nicht so ohne weiteres möglich ist, den Laufindex als Bestandteil eines Variablennamens anzusprechen.
(Mit allen Versuchen, den Laufindex i in eine Makrovariable zu bringen, bin ich gescheitert.)

Wenn ich Ihre Lösung richtig verstanden habe, wird in der Zeile

 array vars&einszwei
die Definition des Variablenarrays begonnen (kein Semikolon!)
und im Schritt
 %scan(&marker,&i)&einszwei
fortgesetzt.
Das abschließende Semikolon befindet sich am Ende der %do-Schleife (?)

genau

Genau so ist es, der Makro baut die Array-Anweisung zusammen. Das abschließende Semikolon der Array-Anweisung steht zwischen %end und %mend.

Danke, wieder etwas

Danke, wieder etwas gelernt!

MM

Grundlagen ...

Hallo,
es scheint einiges grundsätzliches unklar zu sein.
Vielleicht hilft lesen, z.B. in der Online Doc (SAS Macro Language Reference, dort: Introduction, dort: Getting started with the Macro Facility)
oder hier (gefunden über google, Suche nach "macro sprache" und "los suchen".
Ansonsten ist wieder mal vergessen gegangen, dass eine Macro-Sprach nur dazu da ist aus Quell-Text wieder Quelltext zu erzeugen! Eine %let-Anweisung nimmt nur die Zeichen auf, die rechts vom Zuweisungs- (Gleichheits-) Zeichen stehen. Sonst nichts.
Wenn man "etwas" zusammensetzen will, dann nur so

%let String=%scan(&marker., 1);
%let M1=&String.1;
%put INFO: M1=&M1.;
Wenn man statt der '1' jeweils die Schleifenvariable ii schreibt, werden die Macro-Variablen M1, M2, ... definiert
%let anzm=5;
%let marker=A B C;
%macro MakeMVar;
  
%let String=%scan(&marker., 2); /* nimm den 2-ten Wert aus MARKER */
  
%do ii=1 %to &anzm.;
    
%let M&ii.=&String.&ii.;
    
%put INFO: M&ii.=&&M&ii..;
  
%end;
%mend;
%MakeMVar;
Wenn man jetzt noch die JJ-Schleife (über alle Worte aus MARKER) drüberstellt, werden die Macro-Variablen M1, M2, ... jeweils X mal definiert (A1, A2, ... B1, B2, ... C1, C2, ...) und das ist der Code:
%let anzm=5;
%let marker=A B C;
%macro MakeMVar;
%do jj=1 %to 999.;
  
%let String=%scan(&marker., &jj.);
  
%if &String. EQ %then %do;
    
%let jj=999;               /* Schleifen-Abbruch */
  
%end;
  
%else %do;
    
%do ii=1 %to &anzm.;
      
%let M&ii.=&String.&ii.;
      
%put INFO: M&ii.=&&M&ii..;
    
%end;
  
%end;
%end;
%mend;
%MakeMVar;
Immer dran denken: Sobald Kontroll-Strukturen ins Spiel kommen geht's (in der SAS Macro-Sprache) nicht mehr ohne %Macro und %mend aussen rum!

Gruß
Hans Kneilmann, Schäfer Shop GmbH (SSI)

Korrektur zum Beitrag vom 22. Juni 2007, 08:45

Hallo,
eine kleine Korrektur. Danke an "unseren" Ex-Azubi, der hat den Fehler im dritten Code-Block gefunden.
Hier die korrekte Version:

%let anzm=5;
%let marker=A B C;
%macro MakeMVar;
%do jj=1 %to 999 ;    /* hier 999 ohne Punkt danach!!! */
  
%let String=%scan(&marker., &jj.);
  
%if &String. EQ %then %do;
    
%let jj=999;               /* Schleifen-Abbruch */
  
%end;
  
%else %do;
    
%do ii=1 %to &anzm.;
      
%let M&ii.=&String.&ii.;
      
%put INFO: M&ii.=&&M&ii..;
    
%end;
  
%end;
%end;
%mend;
%MakeMVar;

Gruß
Hans Kneilmann, Schäfer Shop GmbH (SSI)

%do anstelle von do

Vielen Dank,

natürlich rühren meine Probleme von Unklarheiten beim Anwenden von Macros her, obwohl mir das Prinzip schon klar ist.
Wenn ich Ihre Lösung recht verstehe, dann
- verwenden Sie %do anstelle von do
(Laufindex ii ist dann Makro-Variable) und kann im Makro über
&ii. angesprochen werden,
- wird String im %Let-Statement

   %let M&ii.=&String.&ii.;
interpretiert, weil es Makrovariable ist.

Ihre Lösung wird mir in vielen ähnlichen Fälle "dynamischer Variablen-Verwaltung" helfen.
Freundlichen Gruß

Meinhard Mende,
Uni Bonn

genau

Genau so ist es.
Mit %do wird (in meinem Beispiel) eine Macro-Schleife eingeleitet, die Base-Code vor der SAS-Base-Laufzeit erzeugt. Erst nach dem SAS-Macro-Umsetzer ist das SAS-Base dran, und erst dabei wird dann ein DO zur Laufzeit abgearbeitet. Den ganzen erzeugten Code sieht man erst jetzt (dank options mprint;) wunderschön im LOG.

Faustregel: Macro-Sprache ist wie tippen von Code-Zeilen, nur eleganter.

Gruß aus'm Westerwald (ist fast um die Ecke)
Hans Kneilmann, Schäfer Shop GmbH (SSI)

Mehr Klarheit

Danke!
Die Hinweise verhelfen mir zu mehr praktischem Durchblick.

Gruß vom Venusberg
Meinhard Mende