Community deutschsprachiger SAS-Anwender und -Programmierer

Antworten
Dies ist eine offene Gruppe. Melden Sie sich an und klicken Sie auf die Schaltfläche „Gruppe beitreten“, um Mitglied zu werden und damit zu beginnen, Beiträge in dieser Gruppe zu veröffentlichen.
Highlighted
Frequent Contributor
Beiträge: 118
Spiegel Online Rätsel als SAS Code Kata

Hallo zusammen,

zur Abwechslung einmal eine kleine Aufgabe an alle CoDe SAS Mitglieder.

Auf Spiegel Online fand ich ein spannendes Rätsel unter: http://www.spiegel.de/wissenschaft/mensch/raetsel-der-woche-wie-viele-schliessfaecher-stehen-offen-a...

Dort wurde eine mathematische Lösung vorgestellt, aber es wäre durchaus auch eine algorithmische Lösung des Problems denkbar.

Ich würde daher das Problem als kleine Code Kata für alle interessierten SAS Programmierer vorschlagen. Hierbei handelt es sich um eine kleine Übungsaufgabe, um neue Techniken oder Programmiermethoden auszuprobieren und zu üben.

Aus eigener Erfahrung kann ich bestätigen, dass man bereits durch eine kleine Code Kata schon einige interessante Einsichten gewinnen kann. Den größten Vorteil kann man jedoch aus einer Code Kata ziehen, wenn man seine Ergebnisse mit anderen Anwendern austauscht.

Mein Vorschlag wäre daher ein SAS Makro zu erstellen, dass die Anzahl der offenen Schließfächer und die Nummern der geöffneten Fächer als Bericht erzeugt.

Die Anzahl der Schließfächer soll per Parameter konfigurierbar sein.

Somit ergibt sich die folgende Makrosignatur:

%macro reportOpenLockers(countOfLockerDoors);

  /* ... */

%mend reportOpenLockers;

Aufgerufen werden kann das Makro dann beispielsweise für 100 Schließfächern so:

%reportOpenLockers(100);

Sie können sich für diese Aufgabe selbst ein Ziel setzen und beispielsweise das Makro besonders elegant und lesbar implementieren oder die Businesslogik in unterschiedlichen SAS Technologien wie Arrays, Hashtables oder PROC DS2 umzusetzen.

Ich werde dieses Makro selbst implementieren und nächsten Freitag (17.7.) an dieser Stelle meine Lösung vorstellen.

Alle interessierten Programmierer können aber ebenso hier ihre Lösung vorstellen und diskutieren.

Ich bin auf die Ergebnisse und Dikussionen gespannt.

Viele Grüße,

Andreas Menrath

Occasional Contributor
Beiträge: 8
Re: Spiegel Online Rätsel als SAS Code Kata

Hallo Herr Menrath,

sehr gute Idee mit dem Rätsel!

Anbei meine Lösung mit einem Data-Step. Ein Report kommt nicht heraus.

Die zum Schluss geöffneten Schließfächer werden ins Log ausgegeben.

Der Stand nach jedem "Rundgang" wird in einer Tabelle gespeichert und kann von dort aus ausgegeben werden.

Entschieden habe ich mich für die Speicherung des Zustands in einer(!) alphanumerischen Variablen, um den Befehl (und nicht die Funktion) substr nutzen zu können.

Die Umsetzung hat Spaß gemacht. Ich konnte mal wieder sehen, wie schnell und kurz man Fragestellungen in SAS in einem einzigen Data-Step lösen kann.

Sicherlich kann man das Makro noch schöner, ausführlicher und abgesicherter umsetzen...

Schönen Abend!

%macro reportOpenLockers(countOfLockerDoors,zu=X,auf=O);


data SCHLIESSFACH (drop=i j);

      attrib SCHLIESSFACH format=$&countOfLockerDoors..;

      /* Schleife i: Rundgänge des Hausmeisters */

      do i=1 to &countOfLockerDoors.;

           /* Schleife j: Je Rundgang alle Schließfächer */

           do j=i by i to &countOfLockerDoors.;

                if mod(j,i)=0 then

                /* jedes i-te Schließfach ändern... */

                /* ...wenn zu (oder beim 1. Mal unbekannt) dann auf */

                     if substr(SCHLIESSFACH,j,1) in (' ',"&ZU.") then do;

                          substr(SCHLIESSFACH,j,1) = "&AUF.";

                     end;

                     else do;

                     /* ...wenn auf dann zu */

                          substr(SCHLIESSFACH,j,1) = "&ZU.";

                     end;

           end; /* Ende Schleife j */

           /* Ausgabe des aktuellen Stands in die Tabelle */

           output;

      end; /* Ende Schleife i */

      /* Ausgabe der noch offenen Schließfächer ins Log */

      do i=1 to &countOfLockerDoors.;

           if substr(SCHLIESSFACH,i,1) in ("&AUF.") then do;

                put i=;

           end;

      end;

run;


%mend reportOpenLockers;


%reportOpenLockers(100);

Occasional Contributor
Beiträge: 6
Re: Spiegel Online Rätsel als SAS Code Kata

Hallo,

auch ich habe das gerade eben mal ausprobiert, weil ich recht neu in SAS bin. Ist auf jeden Fall eine gute Übung. Hat Spass gemacht.

*1 ist offen;

*0 ist geschlossen;

%macro ReportOpenLockers(count);

data tueren (drop=i j);

array lockers[&count.] ;

*alle array variablen auf eins setzen;

do i=1 to &count.;

  lockers = 1;

end;

*zwei Scheifen durchlaufen;

do j=2 to &count.;

do i=j to &count. by j;

  if lockers = 1 then lockers = 0;

  else if lockers = 0 then lockers = 1;

end;

end;

run;

proc transpose data=tueren out=tueren;

run;

proc print data=tueren;

  where Col1 = 1;

run;

%mend ReportOpenLockers;

%ReportOpenLockers(100);

Viele Grüße

Sven

Frequent Contributor
Beiträge: 118
Re: Spiegel Online Rätsel als SAS Code Kata

Hallo zusammen,

wie versprochen möchte ich auch meine Lösung vorstellen:

%macro reportOpenLockers(countOfLockerDoors);

     proc format;

          value open 0 = "closed"

                                                 1 = "open";

     run;

     data lockerinfo;

          /* initialize */

          length lockerNumber status i 8;

          format status open.;

          array lockerDoor {&countOfLockerDoors.} (&countOfLockerDoors. * 0) ;

          /* business logic to calculate locker status */

          do i = 1 to &countOfLockerDoors.;

              lockerDoor2flip = i;

              /* inner loop flips each i-th lockerdoor */

              do while (lockerDoor2flip <= &countOfLockerDoors.);       

                   lockerDoor[lockerDoor2flip] = NOT lockerDoor[lockerDoor2flip];

                   lockerDoor2flip+i;

              end;

          end;

          /* pivot */

          do i=1 to &countOfLockerDoors.;

              lockerNumber = i;

              status = lockerDoor;

              output;

          end;

          keep lockerNumber status;

     run;

     /* reporting */

     proc sql noprint;

          select count(*) into :countOpen

              from lockerinfo

              where status = 1;

     quit;

     title "&countOpen. open locker doors found";

     proc print data=lockerinfo(where=(status=1)) noobs;

          var lockerNumber status;

     run;

     /* cleanup */

     proc delete data=lockerinfo;

     run;

%mend reportOpenLockers;

%reportOpenLockers(100);

Ich muss sagen, dass auch mir das Implementieren Spaß gemacht hat und ich auch wieder etwas gelernt habe.

Beim Anspruch einen möglichst eleganten Code abzuliefern, habe ich u.a. ein längst vergessenes Feature wiederentdeckt:

beim Initialisieren des Arrays kann man mit der Syntax (n * Wert) n-fach einen Initialisierungswert angeben. Das spart mir eine Schleife, in der überall der Wert 0 gesetzt wird.

Den Status der Schließfachtür habe ich als Boolean implementiert. Anfangs hatte ich auch noch das folgende Codeschnipsel im Code stehen:

if(lockerDoor[locker2flip]) then do;

  lockerDoor[locker2flip] = 0;

end;

else do;

     lockerDoor[locker2flip] = 1;

end;

Dann wurde mir bewusst, dass es auch einfacher geht, indem der Boolsche Wert mit dem NOT Operator einfach negiert wird.

Insgesamt fand ich es auch spannend die anderen Lösungen zu sehen und zu vergleichen. Das man die Lösung auch ohne Arrays angehen kann, hätte ich z.B. als ich die Aufgabe gestellt habe, nicht erwartet.

Vielen Dank an alle Mutigen, die ihre Lösung mit der CoDe SAS Community geteilt haben! Weitere Lösungen können weiterhin gerne gepostet werden.

Viele Grüße,

Andreas Menrath