Ein paar Worte vorabHome   Letzte MeldungenNews   Index der Kapitel und der besprochenen FunktionenIndex   Wer ich bin, warum ich diese Seiten mache, KontaktImpressum   Ich freue mich über jeden Eintrag im Gästebuch!Gästebuch   Einige Links zu anderen AutoLisp-SeitenLinks   Copyrights und DisclaimerRechts
Hier können die kompletten Seiten als ZIP-File heruntergeladen werden!

Berechnen von arithmetischen Ausdrücken in der Kommandozeile Sitz!Platz!Fass!
Das Verschachteln von Ausdrücken Alte Schachtel!
Das Speichern von Werten in Variablen Gebunkert
Verhindern der Evaluation mit Quote Bergbäche
Erzeugen von einfachen Listen in AutoLisp Brot,Eier,Käse
Einfache Funktionen zur Listenbearbeitung ...um die Wurst
Funktionen für den Zugriff auf Listenelemente Was ein Salat!
Über Haupt- und Nebeneffekte von Funktionen Schwer schuften
Das Definieren von eigenen Funktionen in AutoLisp Ostfriesischer...
Lokale Variablen und Funktionsargumente in AutoLisp Kondome!
Das Laden von Programmdateien in AutoLisp Banküberfall
Verzweigung in Funktionen aufgrund von Entscheidungen Wenn das Wort...
Zusammenfassen von Entscheidungen mit den Logik-Funktionen Ins Schweinderl
Mehrfach-Verzweigungen in AutoLisp mit Cond 3. Strasse links
Schleifen zum Steuern des Ablaufs in AutoLisp-Funktionen Wie im Fernsehen
Testfunktionen zum Steuern von Schleifen in AutoLisp Schwanger?
Gleichheitstests als Schleifenkriterium in AutoLisp Noch gleicher?
Zeichneketten-Bearbeitung in AutoLisp Rauchzeichen
Funktionen zur Konvertierung von Datentypen in AutoLisp Wasser zu Wein
Komplexere Funktionen für die Bearbeitung von Listen in AutoLisp Nicht arbeiten...
Das Erzeugen von anonymen Funktionen mit lambda Schwarze Kutte
Das Bearbeiten von Listenelementen mit foreach Jedem das Seine
Erzeugen und Verwenden von Assoziationslisten in AutoLisp Beim Psychiater
Zugriff auf Geometriedaten und Erzeugen von Geometrieelementen Ententanz
Der Umgang mit Auswahlsätzen in AutoLisp Jung gefreit, ...
Auswahl von AutoCAD-Zeichnungsgeometrie mit ssget Raffgierig!
Verändern von Zeichnungs-Geometrie mit entmod Flickschusterei
Das Erzeugen von Geometrie mit entmake Houdini
Über Programmierstile in AutoLisp, Teil 1 Emma
Über Programmierstile in AutoLisp, Teil 2 Sti(e)lblüten
Über Programmierstile in AutoLisp, Teil 3 Eingewickelt
Über Programmierstile in AutoLisp, Teil 4 Doofe Frisur?


Zum den Seiten für Fortgeschrittene

Zu den ActiveX-Seiten

Meine Private HP mit Fotos, Gedichten, Musik und Postkartenversand

Mein Online-Lexikon der Fotografie

Mein völlig abgedrehtes Reisebüro










AutoLISP bietet einige weitere Funktionen zur Bearbeitung von Listen, die bisher nicht besprochen wurden. Es handelt sich dabei um (mapcar), (apply), (foreach) und (assoc). Wir werden uns zunächst mit (mapcar) und (apply) befassen und dabei auch (lambda) mit besprechen, das zwar keine Listenbearbeitungsfunktion ist, aber sehr oft im Zusammenhang mit (mapcar) verwendet wird. Die gemeinsame Behandlung bietet sich also an. Als letztes Kapitel über Listenbearbeitung werden wir uns dann mit (assoc) und den Assoziationslisten befassen. Diese Art von Listen ist der Schlüssel zur AutoCAD-Geometriedatenbank.

Die Funktion (mapcar) wendet eine andere Funktion auf Listen an. (mapcar) erhält mindestens zwei Argumente, nämlich einen Ausdruck, der die anzuwendende Funktion repräsentiert, und eine Liste, auf die die Funktion anzuwenden ist. Ein Beispiel - zuächst einmal erzeuegen wir eine Liste mit ein paar Zahlen:
(setq zahlenliste '(4 15 3 7 11))
    =>   (4 15 3 7 11)
                  
Wir wollen alle Zahlen in dieser Liste um eins erhöhen. Dazu bietet sich natürlich die Inkrementfunktion (1+ ...) an. Wenden wir also mit Hilfe von (mapcar) diese Funktion auf die Liste zahlenliste an:
(mapcar '1+ zahlenliste)
    =>   (5 15 4 8 12)
                  
(mapcar) evaluiert alle seine Argumente. Daher müssen wir das Symbol 1+ quotieren. Das Symbol zahlenliste darf natürlich nicht quotiert werden, da wir ja (1+) nicht auf das Symbol, sondern den daran gebundenen Wert anwenden möchten. Dieser gebundene Wert ist die Liste, die wir erzeugt haben.

Im Prinzip kann (mapcar) eine unbegrenzte Anzahl von Argumenten erhalten. Praktisch wird aber die Anzahl der Argumente durch die Funktion bestimmt, die von (mapcar) auf die weiteren Argumente angewendet werden soll. In unserem Beispiel war (1+) die auszuführende Funktion. Da (1+) immer nur ein Argument erhält, müssen wir genau eine Liste an (mapcar) mitschicken, aus der dann nacheinander die Argumente für (1+ ...) entnommen werden.

Ein anderes Beispiel: Wir wollen eine Liste, die mehrere Winkel in Grad enthält, in das Bogenmass konvertieren. Dazu brauchen wir zunächst eine Umrechnungsfunktion. Diese definieren wir so:
(defun grad-zu-bogen(winkel)
  (* pi(/ winkel 180))
)
                  
Wir gehen nun davon aus, dass eine Liste namens gwliste eine uns unbekannte Anzahl von Grad-Winkeln enthält, die umgerechnet und in bwliste gespeichert werden sollen. Ohne Inhalt oder Länge von gwliste zu kennen, können wir die Umrechnung durchführen.
(setq bwliste
  (mapcar 'grad-zu-bogen gwliste)
)
                  
Auch in diesem Beispiel wurde nur eine Liste an (mapcar) übergeben, da auch die Funktion (grad-zu-bogen) nur ein Argument erwartet. Doch nun zu einem Beispiel, bei dem die Ausführungs-Funktion zwei Argumente erwartet. Nehmen wir dazu die Funktion (+ ...). Natürlich kann (+ ...) auch mehr als zwei Argumente erhalten, wir beschränken uns aber erst einmal auf zwei. Wir brauchen also als Argumente für (mapcar) zwei Listen mit Zahlen.
(setq
  zahlen1 '(4 2 11 14 3 8)
  zahlen2 '(6 6 2 11 18 5)
)
                  
Nun wenden wir (mapcar) an und erhalten diese Liste als Rückgabe:
(mapcar '+ zahlen1 zahlen2)
    =>  (10 8 13 25 21 13)
                  
Noch ein weiteres Beispiel zur Verdeutlichung: AutoCAD-Punkte werden als Listen mit drei Zahlen verarbeitet. (car) gibt uns die X-Koordinate, (cadr) den Y-Wert und (caddr) den Z-Wert (Dieser muss nicht unbedingt vorhanden sein - AutoCAD akzeptiert auch 2D-Punkte, Z wird dann automatisch auf den Wert der Systemvariablen "ELEVATION" gesetzt.)

Die Aufgabenstellung ist nun folgende: In einer Liste, von der uns nur der Name bekannt ist, sind Punkte gespeichert. Wir müssen aus irgendwelchen Gründen überprüfen, ob der Y-Wert 4 doppelt vorhanden ist. Um diese Prüfung durchzuführen, brauchen wir keine Programmschleife zu schreiben, wenn wir ein bisschen geschickt vorgehen. Wir klären zunächst, wie wir eine Liste bekommen, die nur die Y-Koordinaten enthält. Ganz einfach, wir wenden (cadr) mit (mapcar) auf die Liste an. Obwohl wir den Inhalt der Liste als unbekannt voraussetzten, folgt hier ein kleines Ersatzbeispiel mit bekannten Werten, damit das Beispiel nachzuvollziehen ist:
(setq punkteliste
 '( (3 12 0)
    (8 4 0)
    (9 2 0)
    (5 5 0)
    (2 4 0)
    (1 1 0)
    (3 0 0)
  )
)

(mapcar 'cadr punkteliste)
    => (12 4 2 5 4 1 0)
                  
Es ist offensichtlich, dass der Y-Wert 4 doppelt vorkommt. Wie kann man dies aber in einer unbekannten Liste testen? Wir nutzen dazu die Funktion (member). Wie wir wissen, gibt (member) den Rest der Liste ab der Stelle zurück, an der die 4 erstmals vorkommt.
(member 4(mapcar 'cadr punkteliste))
    => (4 2 5 4 1 0)
                  
Um zu klären, ob die 4 doppelt vorhanden ist, müssen wir (member) einfach noch einmal anwenden, und zwar auf den Rest der Liste ohne die erste gefundene 4. Diese entfernen wir mit (cdr).
(member 4
  (cdr
    (member 4
      (mapcar 'cadr punkteliste)
    )
  )
)
    =>  (4 1 0)
                  
Das ist schon unser fertiger Prüfausdruck, den wir auf jede beliebige Punkteliste anwenden können. Wir können sogar noch weiter gehen und eine Testfunktion daraus machen, mit der wir jeden beliebigen Y-Wert auf doppeltes Vorhandensein prüfen können:
(defun doppelter-ywert(ywert liste)
  (member ywert
    (cdr
      (member ywert
        (mapcar 'cadr liste)
      )
    )
  )
)
                  
Es sollte noch ein Wort über die Rückgabe verloren werden. Die Funktion gibt dann, wenn der Y-Wert nicht doppelt vorkommt, nil zurück. Ist er aber mindestens zweimal vorhanden, wird ein Listenrest zurückgegeben. Dieser Listenrest ist genausogut wie T oder jedes andere Symbol, das nicht nil ist, zu interpretieren. Sie wissen ja, dass in LISP alles wahr ist, was ungleich nil ist.

Wir wenden unsere Testfunktion noch einmal auf unsere Beispiel-Punkteliste an:
(doppelter-ywert 4 punkteliste)
    =>  (4 1 0)

(doppelter-ywert 5 punkteliste)
    =>  nil
                  
Was passiert, wenn wir von (mapcar) die Funktion (+ ...) auf zwei Listen anwenden lassen, die unterschiedlich lang sind?
(setq
  zahlen1 '(4 2 11 14 3 8 10 3)
  zahlen2 '(6 6 2 11 18 5)
)

(mapcar '+ zahlen1 zahlen2)
    =>  (10 8 13 25 21 13 10 3)
                  
Wir erhalten hier ein korrektes Ergebnis: Da die Funktion (+ ...) auch dann definiert ist, wenn sie nur ein Argument erhält, gibt es keine Fehlermeldung. Der Ablauf der (mapcar)-Ausführung findet also folgendermassen statt:
(+ 4 6) ; ergibt 10
(+ 2 6) ; ergibt 8
  ... bis ...
(+ 8 5) ; ergibt 13
(+ 10)  ; ergibt 10
(+ 3)   ; ergibt 3
                  
Verwenden wir allerdings eine Funktion, die zwingend zwei Argumente vorschreibt, dann müssen auch die beiden Listen gleichlang sein.
(setq symbole '(a b c d e)) => (a b c d e)
(setq werte '(1 2 3 4 5))   => (1 2 3 4 5)
(mapcar 'set symbole werte) => (1 2 3 4 5)
!a                          => 1
!e                          => 5
                  
In diesem Beispiel haben wir eine Liste mit Symbolnamen und eine Liste mit Werten angelegt. Durch die Anwendung von (mapcar) haben wir dann den Symbolen die Werte zugeordnet. (set) gibt immer den zugeordneten Wert zurück, daher ist die Rückgabe von (mapcar) eine Liste mit den Rückgaben der 5 (set)-Aufrufe. Die Rückgabe ist hier aber nebensächlich, da bei Anwendung von (set) der Nebeneffekt die Hauptsache ist.

Wenn wir in diesem Fall (mapcar) mit zwei unterschiedlich langen Listen aufgerufen hätten, wäre die Sache mit einer Fehlermeldung beendet worden.