Tausche zwei Variablen in Elisp

20

Angenommen, ich habe

(setq a 1 b 2)

Wie kann ich die Werte von aund bohne Verwendung einer temporären Variablen elegant austauschen ?

PythonNut
quelle
Ich erinnere mich an die Swap-Operation aus Programmierbeispielen vor vielen Jahren, aber ich glaube nicht, dass ich jemals eine solche "Swap" -Operation gebraucht habe. Wo finden Sie, dass Sie so etwas brauchen?
Stefan
@ Stefan dieses Mal schreibe ich eine Funktion, die zwei Argumente nimmt, und ich möchte sicherstellen, dass das erste Argument das kleinere der beiden ist.
PythonNut
1
@PythonNut, nun, Sie können das erste Argument an (min a b)und das zweite an binden (max a b). Dies ist eine Lösung. Einige werden argumentieren, dass dies zwei Vergleiche erfordert, wenn einer ausreicht, das ist richtig. Sie können mit einem Vergleich noch funktionaler umgehen, zum Beispiel mit destrukturierendem Binden (cl-destructuring-bind (a . b) (if (< a b) (cons a b) (cons b a)) ...). Das ist ein anderer Weg.
Mark Karpov
1
@Mark true, aber zumindest für mich fühlt sich das so an, als würde man Fliegen mit Handgranaten schlagen. cl-destructuring-bindist ein lächerlich mächtiges Werkzeug für diesen Job.
PythonNut

Antworten:

18

Wenn das Gedächtnis mir gut tut und Sie bereit sind, es zu verwenden, cl-libdann:

(cl-rotatef a b)

Beachten Sie, dass dies die Common-Lisp-Methode zur Lösung des Problems ist.

Mark Karpov
quelle
20

Das ist die elegante Sprache, die ich benutze ;-).

(setq a  (prog1 b (setq b  a)))
Drew
quelle
1
Hey, das ist ordentlich. Ich werde es im Hinterkopf behalten, wenn die Leistung jemals ein Problem darstellt.
PythonNut
1
Genial und einfach.
Name
1
Oh, es ist keineswegs originell bei mir. Aber es ist wahrscheinlich der Hauptnutzungszweck, den ich benutze prog1.
Drew
1
Das ist so ziemlich das, worauf sich das cl-rotatefMakro ausdehnt.
abo-abo
6

Wenn es sich um ganze Zahlen handelt:

(setq a (logxor a b))
(setq b (logxor a b))
(setq a (logxor a b))

:)

jtgd
quelle
2
Der Vollständigkeit halber sollten Sie auch den folgenden Klassiker einschließen: a = a + b, b = a - b, a = a - b. Übersetzt nach Emacs Lisp natürlich :-D
Mark Karpov
1
Richtig, und der Vollständigkeit halber möchte ich darauf hinweisen, dass in asm oder C der XOR-Trick für alles funktioniert; Register, Speicher, Ints, Floats, Structs, Strings (gleich lang) ... In Lisp denke ich nur Ints. Für große Speicherblöcke ist es schön, den temporären Puffer nicht zu benötigen.
Dienstag,
@jtgd: Bei großen Speicherblöcken können Sie Segment für Segment mit einem kleinen Puffer tauschen.
Clément